package com.uinnova.product.eam.service.cj.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.binary.core.exception.BinaryException;
import com.binary.core.exception.MessageException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.uinnova.product.cj.feign.dto.PlanDesignInstanceDTO;
import com.uinnova.product.cj.feign.dto.PlanDesignShareRecordDTO;
import com.uinnova.product.cj.feign.dto.PlanVersionDTO;
import com.uinnova.product.eam.base.enums.ResultCodeEnum;
import com.uinnova.product.eam.base.exception.ServerException;
import com.uinnova.product.eam.base.local.TaskFromWorkflowContext;
import com.uinnova.product.eam.base.local.TaskFromWorkflowContextValue;
import com.uinnova.product.eam.comm.model.es.*;
import com.uinnova.product.eam.feign.workable.FlowableFeign;
import com.uinnova.product.eam.feign.workable.entity.*;
import com.uinnova.product.eam.model.asset.ShareMsgDTO;
import com.uinnova.product.eam.model.bm.PushParams;
import com.uinnova.product.eam.model.bm.ReleaseValidResponse;
import com.uinnova.product.eam.model.cj.domain.*;
import com.uinnova.product.eam.model.cj.enums.*;
import com.uinnova.product.eam.model.cj.request.PlanDesignInstanceAddRequest;
import com.uinnova.product.eam.model.cj.request.PlanDesignInstanceQueryRequest;
import com.uinnova.product.eam.model.cj.request.PlanDesignInstanceUpdateRequest;
import com.uinnova.product.eam.model.cj.request.ProcessApprovalRequest;
import com.uinnova.product.eam.model.cj.utils.ZipUtils;
import com.uinnova.product.eam.model.cj.vo.*;
import com.uinnova.product.eam.model.constants.Constants;
import com.uinnova.product.eam.model.constants.FlowableConstant;
import com.uinnova.product.eam.model.constants.NoticeConstant;
import com.uinnova.product.eam.model.dto.ApproveParam;
import com.uinnova.product.eam.model.dto.DiagramParamDto;
import com.uinnova.product.eam.model.enums.ConflictEnum;
import com.uinnova.product.eam.model.vo.MinePlanQueryVo;
import com.uinnova.product.eam.model.vo.SharePublishAssertMsgVo;
import com.uinnova.product.eam.model.vo.WorkbenchChargeDoneVO;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.eam.service.asset.IAttentionSvc;
import com.uinnova.product.eam.service.asset.IRecentlyViewSvc;
import com.uinnova.product.eam.service.bm.FlowModelMergeSvc;
import com.uinnova.product.eam.service.cj.dao.*;
import com.uinnova.product.eam.service.cj.service.*;
import com.uinnova.product.eam.service.cj.utils.CreateTableService;
import com.uinnova.product.eam.service.es.EamCategoryDesignDao;
import com.uinnova.product.eam.service.exception.BusinessException;
import com.uinnova.product.eam.service.fx.GeneralPushSvc;
import com.uinnova.product.eam.service.handler.PushFacadeService;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CiGroupPage;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.base.diagram.util.CommonUtil;
import com.uinnova.project.service.eam.ESDiagramSvc;
import com.uino.api.client.cmdb.IDataSetApiSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.ESCIAttrDefInfo;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.business.dataset.DataSetExeResultSheetPage;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.UserInfo;
import com.uino.bean.permission.query.CSysUser;
import com.uino.dao.cmdb.ESCIClassSvc;
import com.uino.dao.util.ESUtil;
import com.uino.service.cmdb.microservice.impl.CIClassSvc;
import com.uino.service.util.FileUtil;
import com.uino.util.cache.ICacheService;
import com.uino.util.rsm.RsmUtils;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 方案设计实例service实现
 *
 * @author zhaoxin
 */
@Slf4j
@Service
public class PlanDesignInstanceServiceImpl implements PlanDesignInstanceService {

    @Value("${http.resource.space}")
    private String httpResouceUrl;

    @Resource
    private PlanDesignInstanceDao planDesignInstanceDao;

    @Resource
    private PlanChapterInstanceService planChapterInstanceService;

    @Resource
    private PlanSystemRelationDao planSystemRelationDao;

    @Autowired
    private PlanDesignShareRecordDao planDesignShareRecordDao;

    @Autowired
    private DeliverableTemplateService deliverableTemplateService;

    @Autowired
    private TemplateTypeDao templateTypeDao;

    @Resource
    private PlanChapterInstanceDao planChapterInstanceDao;

    @Resource
    private ChapterContextDao chapterContextDao;

    @Resource
    private FlowableService flowableService;

    @Resource
    private PlanChapterQuestionService planChapterQuestionService;

    @Resource
    private CiInfoService ciInfoService;

    @Resource
    private DirRelationPlanService dirRelationPlanService;

    @Autowired
    private DirRelationPlanDao dirRelationPlanDao;

    @Resource
    private ItArchitectureDesignDirQueryService itArchitectureDesignDirQueryService;

    @Resource
    private PlanArtifactService planArtifactService;

    @Resource
    private IUserApiSvc userApiSvc;

    @Value("${local.resource.space}")
    private String localPath;

    @Value("${http.resource.space}")
    private String httpPath;

    @Value("${process.definition.key}")
    private String processDefinitionKey;

    @Resource
    private WorkbenchChargeDoneSvc workbenchChargeDoneSvc;

    @Resource
    private IAttentionSvc attentionSvc;

    @Resource
    private IRecentlyViewSvc recentlyViewSvc;

    @Resource
    private FxDiagramSvc fxDiagramSvc;

    @Resource
    private EamDiagramRelationSysService eamDiagramRelationSysService;

    @Resource
    private ESDiagramSvc esDiagramSvc;

    @Resource
    private FlowModelMergeSvc flowModelMergeSvc;

    @Resource
    private GeneralPushSvc generalPushSvc;

    @Resource
    private PushFacadeService pushFacadeService;

    @Resource
    private ESDiagramApiClient diagramApiClient;

    @Resource
    private IDataSetApiSvc dataSetApiSvc;

    @Resource
    private ICISwitchSvc ciSwitchSvc;

    @Resource
    @Lazy
    private IEamNoticeService eamNoticeService;

    @Resource
    private EamCategorySvc categorySvc;

    @Autowired
    private RsmUtils rsmUtils;

    @Resource
    private EamCategoryDesignDao categoryDesignDao;

    @Resource
    private ShareService shareService;

    @Resource
    private FlowableFeign flowableFeign;
    @Resource
    private PlanChapterCollaborateService planChapterCollaborateService;

    @Resource
    private ICacheService iCacheService;

    @Resource
    private DiagramApproveRltSvc diagramApproveRltSvc;

    @Resource
    private PlanInstanceServiceExtend planInstanceServiceExtend;

    @Autowired
    private BmConfigSvc bmConfigSvc;
    @Autowired
    private CIClassSvc ciClassSvc;
    @Autowired
    private ESCIClassSvc classSvc;
    @Autowired
    private ArchReviewDao archReviewDao;
    @Resource
    private PlanModuleAnnotationDao planModuleAnnotationDao;
    @Resource
    private PlanChapterQuestionDao planChapterQuestionDao;
    @Autowired
    private CreateTableService createTableService;

    /**
     * 方案设计新增
     *
     * @param request {@link PlanDesignInstanceAddRequest}
     */
    @Override
    public Long add(PlanDesignInstanceAddRequest request) {
        checkNameWhileAdd(request.getId(), request.getName(), request.getDirType());

        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        String loginCode = currentUserInfo.getLoginCode();
        long time = ESUtil.getNumberDateTime();

        PlanDesignInstance instance = new PlanDesignInstance();

        BeanUtils.copyProperties(request, instance);

        instance.setId(ESUtil.getUUID());
        String secret = request.getName();
        if (!StringUtils.isEmpty(request.getDefaultSystemCiCode())) {
            secret = secret + request.getDefaultSystemCiCode();
        }
        String businessKey = SecureUtil.md5(secret);
        instance.setBusinessKey(businessKey);
        instance.setVersion(0);
        instance.setIsCurrentVersion(true);
        instance.setStatus(PlanStatusEnum.draft.name());
        instance.setCreatorCode(loginCode);
        instance.setCreateTime(time);
        instance.setRecyclable(true);
        instance.setAssetsType(Constants.DESIGN);

        CSysUser cdt = new CSysUser();
        cdt.setLoginCodeEqual(loginCode);
        List<SysUser> sysUserList = userApiSvc.getSysUserByCdt(cdt);
        if (!CollectionUtils.isEmpty(sysUserList)) {
            SysUser sysUser = sysUserList.get(0);
            instance.setCreatorName(sysUser.getUserName());
        }
        if (instance.getDefaultSystemCiCode() != null) {
            setDefaultSystemCiClass(instance);
        }
        DlvrTemplateVO template = deliverableTemplateService.getDlvrTemplateById(instance.getTemplateId());
        if(template!=null){
            instance.setTemplateVersion(template.getTemplateVersion());
        }
        planDesignInstanceDao.saveOrUpdate(instance);

        insertPlanSystemRelation(instance);

        initChapter(request, instance);

        //维护最近查看、最近编辑记录
        addRecentView(instance);

        return instance.getId();
    }

    private void addRecentView(PlanDesignInstance instance) {
        if (instance == null || instance.getId() == null) {
            return;
        }
        CEamRecentlyView ceamRecentlyView = new CEamRecentlyView();
        ceamRecentlyView.setUserId(SysUtil.getCurrentUserInfo().getId());
        ceamRecentlyView.setPlanId(instance.getId());
        ceamRecentlyView.setViewType(2);
        ceamRecentlyView.setViewArchitectureType(1);
        recentlyViewSvc.saveOrUpdateRecentlyView(ceamRecentlyView);
    }

    private void setDefaultSystemCiClass(PlanDesignInstance instance) {
        String defaultSystemCiCode = instance.getDefaultSystemCiCode();
        ESCISearchBean bean = new ESCISearchBean();
        bean.setPageSize(1);
        bean.setCiCodes(ListUtil.list(false, defaultSystemCiCode));
        CiGroupPage ciGroupPage = ciSwitchSvc.queryPageBySearchBean(bean, false, LibType.DESIGN);
        if (ciGroupPage.getTotalRows() == 1) {
            Long classId = ciGroupPage.getData().get(0).getCi().getClassId();
            instance.setDefaultSystemClassId(classId);
        }
    }

    private void initChapter(PlanDesignInstanceAddRequest request, PlanDesignInstance instance) {
        try {
            planChapterInstanceService.initChapter(instance.getId(), request.getTemplateId());
        } catch (Exception e) {
            log.error("新增方案设计时初始化模板异常", e);
        }
    }

    private void insertPlanSystemRelation(PlanDesignInstance instance) {
        insertPlanSystemRelationBatch(ListUtil.list(false, instance));
    }

    private void insertPlanSystemRelationBatch(List<PlanDesignInstance> planList) {
        if (BinaryUtils.isEmpty(planList)) {
            return;
        }

        List<PlanSystemRelation> list = new LinkedList<>();
        for (PlanDesignInstance instance : planList) {
            List<PlanSystemRelation> planSystemRelationList = getPlanSystemRelations(instance);
            list.addAll(planSystemRelationList);
        }

        if (list.size() > 0) {
            planSystemRelationDao.saveOrUpdateBatch(list);
        }
    }

    private List<PlanSystemRelation> getPlanSystemRelations(PlanDesignInstance instance) {
        if (null == instance.getCiCodeList() || instance.getCiCodeList().size() < 1) {
            return new ArrayList<>();
        }
        return instance.getCiCodeList().stream().map(ciCode -> {
            PlanSystemRelation relation = new PlanSystemRelation();
            relation.setPlanId(instance.getId());
            relation.setCiCode(ciCode);
            relation.setStatus(Constants.NO_RELEASE_STATUS);
            return relation;
        }).collect(Collectors.toList());
    }


    @Override
    public Set<String> updatePlanStatus(String status, Long planId) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.termQuery("id", planId));
        builder.must(QueryBuilders.termQuery("status.keyword", status));
        List<PlanDesignInstance> isRelease = planDesignInstanceDao.getListByQuery(builder);
        if (isRelease.size() > 0) {
            throw new BusinessException(ResultCodeEnum.PLAN_REPEAT_PUB);
        }
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        String userName = currentUserInfo.getUserName();
        String loginCode = currentUserInfo.getLoginCode();
        long time = ESUtil.getNumberDateTime();
        PlanDesignInstance instance = new PlanDesignInstance();
        instance.setId(planId);
        instance.setModifierCode(loginCode);
        instance.setModifierName(userName);
        instance.setModifyTime(time);
        if (status.equals(PlanStatusEnum.published.name())) {
            instance.setStatus(PlanStatusEnum.published.name());
            planDesignInstanceDao.saveOrUpdate(instance);

            // 修改关联系统发布状态
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termQuery("planId", planId));
            queryBuilder.must(QueryBuilders.termQuery("status", Constants.NO_RELEASE_STATUS));
            List<PlanSystemRelation> planSystemList = planSystemRelationDao.getListByQuery(queryBuilder);
            planSystemList.forEach(planSystem -> {
                planSystem.setStatus(Constants.IS_RELEASE_STATUS);
                planSystemRelationDao.saveOrUpdate(planSystem);
            });

            // 查询所有系统id列表
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            query.must(QueryBuilders.termQuery("planId", planId));
            query.must(QueryBuilders.termQuery("status", Constants.IS_RELEASE_STATUS));
            List<PlanSystemRelation> systemList = planSystemRelationDao.getListByQuery(query);
            return systemList.stream().map(PlanSystemRelation::getCiCode).collect(Collectors.toSet());
        }
        return Collections.emptySet();
    }

    @Override
    public List<TemplateType> getReleaseTemplateType() {
        List<DlvrTemplateDTO> releaseTemplateList = deliverableTemplateService.getReleaseTemplateList(new DlvrTemplateReq());
        if (releaseTemplateList != null && releaseTemplateList.size() > 0) {
            List<Long> typeId = releaseTemplateList.stream().map(DlvrTemplateDTO::getTypeId).collect(Collectors.toList());
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.termsQuery("id", typeId));
            return templateTypeDao.getListByQuery(boolQueryBuilder);
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public Boolean copyPlanInfoById(Long planId,String planName) {
        long copyPlanId = ESUtil.getUUID();
        PlanDesignInstance copyPlanDesignInstance = planDesignInstanceDao.getById(planId);
        copyPlanDesignInstance.setId(copyPlanId);
        if (planName!=null) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.termQuery("name.keyword", planName));
            List<PlanDesignInstance> listByQuery = planDesignInstanceDao.getListByQuery(boolQueryBuilder);
            if (!listByQuery.isEmpty() && listByQuery.size() > 0) {
                throw new BusinessException("复制修改的模板名称重复,请重新输入",planName);
            }
            copyPlanDesignInstance.setName(planName);
        }else{
            String copyPlanName = getCopyPlanName(copyPlanDesignInstance);
            if (copyPlanName.length() > 50) {
                throw new BusinessException("复制的方案名称超过50",copyPlanName);
            }
            copyPlanDesignInstance.setName(getCopyPlanName(copyPlanDesignInstance));
        }
        copyPlanDesignInstance.setStatus("draft");
        copyPlanDesignInstance.setCreateTime(BinaryUtils.getNumberDateTime());
        copyPlanDesignInstance.setModifyTime(BinaryUtils.getNumberDateTime());
        planDesignInstanceDao.saveOrUpdate(copyPlanDesignInstance);
        //根据方案设计id查找下面所有章节信息
        List<ChapterInstance> chapterInstances = findAllChapterInstance(planId);
        //复制所有章节信息（包括子章节）
        Map<Long,Long> copyMap = new HashMap<>();
        copyChapter(chapterInstances,copyPlanId,copyMap);
        //完成方案设计复制
        return true;
    }

    @Override
    public List<PlanDesignInstance> findPlanDesignList(Integer releaseStatus, Long dirId, String name, String creatorCode) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isBlank(name)) {
            queryBuilder.must(QueryBuilders.termQuery("dirId", dirId));
        } else {
            queryBuilder.must(QueryBuilders.multiMatchQuery(name, "name").operator(Operator.AND).type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
            List<EamCategory> categoryList = categorySvc.queryByRootId(dirId, 1, creatorCode, LibType.PRIVATE);
            Set<Long> dirIds = categoryList.stream().map(EamCategory::getId).collect(Collectors.toSet());
            dirIds.add(dirId);
            queryBuilder.must(QueryBuilders.termsQuery("dirId", dirIds));
        }
        // 是否方案已发布都查询草稿态，根据业务主键判断是否已发布
        queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
        // 在设计库查询
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        queryBuilder.must(QueryBuilders.termQuery("creatorCode.keyword", creatorCode));

        if (releaseStatus != null && (releaseStatus==0 || releaseStatus==1)) {
            String status = releaseStatus == 0?PlanStatusEnum.draft.name():PlanStatusEnum.published.name();
            queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", status));
        }

        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    @Override
    public List<PlanDesignInstance> findPublishedPlanDesignList(String name) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        if (!StringUtils.isEmpty(name)) {
            queryBuilder.must(QueryBuilders.wildcardQuery("name.keyword", "*" + name + "*"));
        }
        List<PlanDesignInstance> listByQuery = planDesignInstanceDao.getListByQuery(queryBuilder);
        List<Long> planIds = listByQuery.stream().map(planDesignInstance -> planDesignInstance.getId()).collect(Collectors.toList());
        Map<String, List<PlanDesignInstance>> planHistoryVersionListByIds = findPlanHistoryVersionListByIds(planIds);
        for (PlanDesignInstance planDesignInstance : listByQuery) {
            Integer version = 1;
            if (!CollectionUtils.isEmpty(planHistoryVersionListByIds.get(planDesignInstance.getBusinessKey()))) {
                version = planHistoryVersionListByIds.get(planDesignInstance.getBusinessKey()).size();
            }
            planDesignInstance.setVersion(version);
        }
        return listByQuery;
    }

    @Override
    public List<PlanDesignInstance> getRecyclePlanByDirId(Set<Long> dirIds) {
        if (CollectionUtils.isEmpty(dirIds)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("dirId", dirIds));
        queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        queryBuilder.must(QueryBuilders.termsQuery("creatorCode.keyword", SysUtil.getCurrentUserInfo().getLoginCode()));
        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    @Override
    public List<PlanDesignInstance> getPublishedPlan(List<Long> dirIds, String name) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published));
        queryBuilder.must(QueryBuilders.termsQuery("assetsDirId", dirIds));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        if (!StringUtils.isEmpty(name)) {
            queryBuilder.must(QueryBuilders.wildcardQuery("name.keyword", "*" + name + "*"));
        }
        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    @Override
    public List<PlanDesignInstance> findPlanDesignListByPlanIds(Long[] planIds, String name) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("id", planIds));
        queryBuilder.must(QueryBuilders.termsQuery("status.keyword", "published"));
        List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (planDesignInstanceList == null || planDesignInstanceList.size() <= 0) {
            return new ArrayList<>();
        }
        if (!StringUtils.isBlank(name)) {
            return planDesignInstanceList.stream().filter(item -> Pattern.compile(Pattern.quote(name), Pattern.CASE_INSENSITIVE).matcher(item.getName()).find()).collect(Collectors.toList());
        }else{
            return planDesignInstanceList;
        }
    }

    @Override
    public Boolean deletePublishedPlan(Long planId) {
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
        if (planDesignInstance == null) {
            throw new BusinessException("方案已被删除!");
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("businessKey.keyword", planDesignInstance.getBusinessKey()));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        query.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
        List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(query);
        if (!CollectionUtils.isEmpty(planDesignInstanceList)) {
            List<Long> publishPlanId = planDesignInstanceList.stream().map(PlanDesignInstance::getId).collect(Collectors.toList());

            //删除方案和资产文件夹关系数据
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termsQuery("planId", publishPlanId));
            dirRelationPlanDao.deleteByQuery(queryBuilder, true);

            // 删除方案关联制品
            planArtifactService.deletePlanArtifactByPlanIds(publishPlanId);

            // 删除资产库发布的和历史版本方案
            planDesignInstanceDao.deleteByIds(publishPlanId);
        }
        workbenchChargeDoneSvc.deleteWorkbenchPublishedChargeDone(planDesignInstance.getBusinessKey(), null);

        // 修改设计库的状态
        BoolQueryBuilder designQuery = QueryBuilders.boolQuery();
        designQuery.must(QueryBuilders.termQuery("businessKey.keyword", planDesignInstance.getBusinessKey()));
        designQuery.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        List<PlanDesignInstance> designPlanList = planDesignInstanceDao.getListByQuery(designQuery);
        if (!CollectionUtils.isEmpty(designPlanList)) {
            designPlanList.forEach(plan -> {
                plan.setModifyTime(ESUtil.getNumberDateTime());
                if (Objects.equals(plan.getStatus(), PlanStatusEnum.published.name())) {
                    plan.setStatus(PlanStatusEnum.draft.name());
                } else if (Objects.equals(plan.getStatus(), PlanStatusEnum.deleted.name())) {
                    plan.setDeleteBeforeStatus(PlanStatusEnum.draft.name());
                }
            });
            planDesignInstanceDao.saveOrUpdateBatch(designPlanList);
        }
        //删除方案的时候删除我的最近查看和我的关注关联表数据
        EamAttention eamAttention = new EamAttention();
        eamAttention.setAttentionId(planId);
        eamAttention.setAttentionType(3);
//        if (planDesignInstance.getDirType() == 11) {
//            eamAttention.setAttentionBuild(3);
//        }
//
//        if (planDesignInstance.getDirType() == 1) {
//            eamAttention.setAttentionBuild(1);
//        }
//        if (planDesignInstance.getDirType() == 110) {
//            eamAttention.setAttentionBuild(6);
//        }
        attentionSvc.cancelAttention(eamAttention);
        EamRecentlyView eamRecentlyView = new EamRecentlyView();
        eamRecentlyView.setPlanId(planId);
        recentlyViewSvc.cancelRecentlyView(eamRecentlyView);
        return true;
    }

    /**
     * 更新最后修改时间
     *
     * @param planId 方案Id
     */
    @Override
    public void updateModifyTime(Long planId) {
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        plan.setModifyTime(ESUtil.getNumberDateTime());
        planDesignInstanceDao.saveOrUpdate(plan);
    }

    @Override
    public List<PlanDesignInstance> queryMyPublishPlan() {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        queryBuilder.must(QueryBuilders.termQuery("creatorCode.keyword",loginCode));
        queryBuilder.must(QueryBuilders.termQuery("status.keyword","published"));
        queryBuilder.must(QueryBuilders.termQuery("assetsType","2"));
        List<PlanDesignInstance> listByQuery = planDesignInstanceDao.getListByQuery(queryBuilder);
        log.info("count:",listByQuery.size());
        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    @Override
    public Boolean updatePlanDiagramIsFlow(Long planId, Integer status) {
        if (planId == null) {
            throw new BusinessException("方案信息不能为空!");
        }
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案错误!");
        }
        // 修改视图状态
        updateDiagramState(planId, status);
        return true;
    }

    /**
     * 方案取消分享
     *
     * @param planDesignShareRecord {@link PlanDesignShareRecord}
     */
    @Override
    public void cancelShareRecord(PlanDesignShareRecord planDesignShareRecord) {
        PlanDesignShareRecord shareRecord = planDesignShareRecordDao.getById(planDesignShareRecord.getId());
        shareRecord.setStatus(PlanShareEnum.CANCEL_SHARING.getStatus());
        planDesignShareRecordDao.saveOrUpdate(shareRecord);
    }

    /**
     * 查询方案
     *
     * @param ids id集合
     * @return 方案集合
     */
    @Override
    public List<PlanDesignInstance> getByIds(Collection<Long> ids) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        TermsQueryBuilder must = QueryBuilders.termsQuery("id", ids);
        boolQuery.must(must);
        return planDesignInstanceDao.getListByQuery(boolQuery);
    }

    @Override
    public Integer deleteByIds(Collection<Long> ids) {
        return planDesignInstanceDao.deleteByIds(ids);
    }

    @Override
    public List<PlanDesignInstance> findPlanListByDirIds(Set<Long> dirIdList) {
        if (CollectionUtils.isEmpty(dirIdList)) {
            return Collections.emptyList();
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("dirId", dirIdList));
        queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        queryBuilder.must(QueryBuilders.termsQuery("creatorCode.keyword", SysUtil.getCurrentUserInfo().getLoginCode()));
        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    @Override
    public void batchPublishPlan(List<Long> planIdList) {
        if (CollectionUtils.isEmpty(planIdList)) {
            throw new BusinessException("方案列表不能为空!");
        }
        for(Long planId : planIdList) {
            System.out.println(planId);
            PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
            if (Objects.equals(PlanStatusEnum.published.name(), planDesignInstance.getStatus())) {
                continue;
            }
            List<PlanChapterVO> chapterList = planChapterInstanceService.getChapterList(planId);
            if (CollectionUtils.isEmpty(chapterList)) {
                throw new BusinessException("获取方案章节错误!");
            }
            Set<Long> chapterIds = chapterList.stream().map(PlanChapterVO::getId).collect(Collectors.toSet());
            // 验证章节内容都已填写
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termsQuery("id", chapterIds));
            List<ChapterContext> contextList = chapterContextDao.getListByQuery(queryBuilder);

            // 发布方案
            handlerPublishPlan(planDesignInstance);
            // 发布视图
            handlerPublishDiagram(contextList, planDesignInstance);

            chapterContextDao.saveOrUpdateBatch(contextList);

            planDesignInstance.setProcessApproval(false);
            planDesignInstance.setStatus(PlanStatusEnum.published.name());
            planDesignInstanceDao.saveOrUpdate(planDesignInstance);
        }

    }

    @Override
    public Map<String, Object> batchCheckPlan(List<Long> planIdList) {
        if (!CollectionUtils.isEmpty(planIdList)) {
            throw new BusinessException("方案主键列表不能为空!");
        }
        Map<String, Object> planProblemMap = new HashMap<>();
        planIdList.forEach(planId -> {
            PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
            if (plan == null) {
                throw new BusinessException("获取方案错误!");
            }
            List<PlanChapterVO> chapterList = planChapterInstanceService.getChapterList(planId);
            if (CollectionUtils.isEmpty(chapterList)) {
                throw new BusinessException("获取方案章节错误!");
            }
            Set<Long> chapterIds = chapterList.stream().map(PlanChapterVO::getId).collect(Collectors.toSet());
            // 验证章节内容都已填写
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termsQuery("id", chapterIds));
            List<ChapterContext> contextList = chapterContextDao.getListByQuery(queryBuilder);
            Map<String, Object> problemMap = handlerChapter(contextList);
            if (!CollectionUtils.isEmpty(problemMap)) {
                planProblemMap.putAll(problemMap);
            }
        });
        if (!CollectionUtils.isEmpty(planProblemMap)) {
            return planProblemMap;
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("result", true);
        return resultMap;
    }

    @Override
    public List<Long> updatePlanRelationSys(Long dirId) {
        Random random = new Random();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("dirId", dirId));
        List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(queryBuilder);
        planDesignInstanceDao.saveOrUpdateBatch(planDesignInstanceList);
        List<Long> collect = planDesignInstanceList.stream().map(PlanDesignInstance::getId).collect(Collectors.toList());
        return collect;
    }

    @Override
    public boolean updatePlanDirType(Integer dirType) {
        List<PlanDesignInstance> instanceList = planDesignInstanceDao.getListByCdt(new PlanDesignInstance());
        instanceList.forEach(plan -> {
            plan.setDirType(dirType);
        });
        planDesignInstanceDao.saveOrUpdateBatch(instanceList);
        return true;
    }

    @Override
    public Map<String, Object> checkPlan(Long planId) {
        if (planId == null) {
            throw new BusinessException("方案主键不能为空!");
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        List<ChapterInstance> chapterList = planChapterInstanceService.findPlanChapterList(planId);
        if (CollectionUtils.isEmpty(chapterList)) {
            throw new BusinessException("获取方案章节错误!");
        }
        checkProcessStartUserIsCurUserCaseUnPassSubmit(plan);
        Set<Long> chapterIds = chapterList.stream().map(ChapterInstance::getId).collect(Collectors.toSet());
        // 验证章节内容都已填写
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("id", chapterIds));
        List<ChapterContext> contextList = chapterContextDao.getListByQuery(queryBuilder);
        Map<String, Object> problemMap = handlerChapterNew(contextList);
        if (!CollectionUtils.isEmpty(problemMap)) {
            return problemMap;
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("result", true);
        //模板类型是否是"架构方案"
        String configJson = bmConfigSvc.getConfigType("AXEA_CONFIG");
        if (StringUtils.isBlank(configJson)) {
            throw new BinaryException("未查询到国投配置，请联系管理员");
        }
        JSONObject conf = JSON.parseObject(configJson);
        TemplateType templateType = getArchReviewTemplateType(conf);
        resultMap.put("archReview", templateType.getId().equals(plan.getTypeId()));
        EamCategory category = categorySvc.getById(plan.getAssetsDirId(), LibType.DESIGN);
        resultMap.put("assertDirExist", category != null);
        return resultMap;
    }

    private void checkProcessStartUserIsCurUserCaseUnPassSubmit(PlanDesignInstance plan) {
        //只看流程中的
        if (plan == null || StringUtils.isBlank(plan.getTaskId())) {
            return;
        }
        TaskResponse taskResponse = flowableFeign.getCurrentTaskDefinitionInfo(plan.getId().toString(), FlowableConstant.PLAN_DEFINITION_KEY1);
        if (taskResponse == null || org.apache.commons.lang.StringUtils.isBlank(taskResponse.getProcessInstanceId())) {
            return;
        }
        PorcessResponse porcessResponse = flowableFeign.getProcessInstanceByProcessInstanceId(taskResponse.getProcessInstanceId());
        if (porcessResponse == null || org.apache.commons.lang.StringUtils.isBlank(porcessResponse.getProcessStartUserId())) {
            return;
        }
        String curLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        if (curLoginCode.equals(porcessResponse.getProcessStartUserId())) {
            return;
        }
        //驳回流程提交人不是流程发起人，提示：xxx已提交评审，请联系该用户处理
        String processStartUserName = porcessResponse.getProcessStartUserId();
        CSysUser cdt = new CSysUser();
        cdt.setLoginCodeEqual(porcessResponse.getProcessStartUserId());
        List<SysUser> users = userApiSvc.getSysUserByCdt(cdt);
        if (!org.springframework.util.CollectionUtils.isEmpty(users)) {
            processStartUserName = users.get(0).getUserName();
        }
        throw new BinaryException(processStartUserName + "已提交评审，请联系该用户处理");
    }

    @Override
    public Long submitApproval(SysUser user, ProcessApprovalRequest request, PlanDesignInstance plan) {
        if (request == null) {
            throw new BusinessException("请求参数不能为空!");
        }
        if (plan.isProcessApproval() && Objects.equals(request.getSign(), Constants.PLAN_APPROVAL)) {
            return -1L;
        }
        if (!BinaryUtils.isEmpty(request.getTaskId())) {
            // 校验重复处理同一任务
            TaskResponse task = flowableFeign.getTaskInfoByTaskId(request.getTaskId());
            Map<String, Object> taskEchoVariables = task.getTaskEchoVariables();
            if (!BinaryUtils.isEmpty(taskEchoVariables) && !BinaryUtils.isEmpty(taskEchoVariables.get("pass"))) {
                return -3L;
            }
            // 校验多审批人处理同一任务
            Boolean existByTaskId = flowableFeign.isExistByTaskId(request.getTaskId());
            if (!existByTaskId) {
                return -4L;
            }
        }
        UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(user.getLoginCode());
        if (userInfo == null) {
            throw new BusinessException("获取用户信息错误!");
        }
        Long templateId = plan.getTemplateId();
        DeliverableTemplate deliverableTemplate = deliverableTemplateService.getDeliverableTemplateById(templateId);
        EamCategory category = null;
        try {
            category = categorySvc.getById(plan.getAssetsDirId(), LibType.DESIGN);
        } catch (Exception e) {
            // 再流程中的方案发布状态是草稿
            plan.setStatus(PlanStatusEnum.draft.name());
            plan.setProcessApproval(false);
            plan.setTaskId("");
            planDesignInstanceDao.saveOrUpdate(plan);
            // 修改方案中视图状态
            updatePlanDiagramIsFlow(request.getPlanId(), 0);

            // 回滚模型视图
            /*if (deliverableTemplate != null && deliverableTemplate.getApprovalType() != null
                    && Objects.equals(deliverableTemplate.getApprovalType(), 2)) {
                diagramProcessSvc.rollBackApproveData(String.valueOf(plan.getId()), 1);
            }*/

            log.error("获取方案发布位置错误：", e);
            throw new BusinessException(e.getMessage());
        }

        TaskResponse taskResponse = null;
        String taskId = "";
        boolean processApproval = true;
        if (Objects.equals(request.getSign(), Constants.PLAN_APPROVAL)) {
            // 如果位置为空，返回固定的编码，前端作特殊化处理
            if (category == null) {
                // 再流程中的方案发布状态是草稿
                plan.setStatus(PlanStatusEnum.draft.name());
                plan.setProcessApproval(false);
                plan.setTaskId("");
                planDesignInstanceDao.saveOrUpdate(plan);
                return -2L;
            }
            // 校验是否存在未修复的问题
            PlanChapterQuestion question = new PlanChapterQuestion();
            question.setPlanId(request.getPlanId());
            question.setQuestionState(QuestionStatusEnum.NOT_RECTIFIED.getState());
            // 存在待验证的数量
            Long num = planChapterQuestionService.countQuestion(question);
            if (num != null && num > 0) {
                throw new BusinessException("存在未整改的问题，提交审批失败!");
            }

            if (deliverableTemplate != null && deliverableTemplate.getApprovalType() != null) {
                if(Objects.equals(deliverableTemplate.getApprovalType(), 1)) {
                    // 开启新版流程审批
                    taskResponse = processApproval(request, plan, user, FlowableConstant.PLAN_DEFINITION_KEY1);
                } else if(Objects.equals(deliverableTemplate.getApprovalType(), 2)) {
                    // 开启旧版流程审批
                    taskResponse = processApproval(request, plan, user, FlowableConstant.PLAN_DEFINITION_KEY1);
                }
            } else {
                // 开启旧版流程审批
                taskResponse = processApproval(request, plan, user, FlowableConstant.PLAN_DEFINITION_KEY1);
            }

            // 修改方案中视图状态
            updatePlanDiagramIsFlow(request.getPlanId(), 2);
        } else if (Objects.equals(request.getSign(), Constants.QUESTION_APPROVAL)) {
            if (StringUtils.isEmpty(request.getTaskId())) {
                throw new BusinessException("任务主键不能为空!");
            }
            // 如果位置为空，发驳回通知返回固定的编码，前端作特殊化处理
            if (!Objects.equals(request.getApproval(), 3) && category == null) {
                // 再流程中的方案发布状态是草稿
                plan.setStatus(PlanStatusEnum.draft.name());
                plan.setProcessApproval(false);
                plan.setTaskId(taskId);
                planDesignInstanceDao.saveOrUpdate(plan);
                // 修改方案中视图状态
                updatePlanDiagramIsFlow(plan.getId(), 0);

                // 回滚模型视图
                /*if (deliverableTemplate != null && deliverableTemplate.getApprovalType() != null
                        && Objects.equals(deliverableTemplate.getApprovalType(), 2)) {
                    diagramProcessSvc.rollBackApproveData(String.valueOf(plan.getId()), 1);
                }*/
                return -2L;
            }
            // 方案同意验证未改问题
            if (Objects.equals(request.getApproval(), 1)) {
                PlanChapterQuestion question = new PlanChapterQuestion();
                question.setPlanId(request.getPlanId());
                question.setQuestionState(QuestionStatusEnum.NOT_RECTIFIED.getState());
                // 存在待验证的数量
                Long num = planChapterQuestionService.countQuestion(question);
                if (num != null && num > 0) {
                    throw new BusinessException("存在未整改的问题，提交审批失败!");
                }
            }

            // 执行审批
            TaskRequest taskRequest = new TaskRequest();
            taskRequest.setTaskId(request.getTaskId());
            if (Objects.equals(request.getApproval(), 1)) {
                taskRequest.setAction(FLOWACTION.ACCETP);
            } else if (Objects.equals(request.getApproval(), 3)) {
                taskRequest.setAction(FLOWACTION.CANCEL);
                // 若当前方案包含子流程 终止所有子流程
                String processInstanceId = request.getProcessInstanceId();
                PorcessResponse processInstance = flowableFeign.getProcessInstanceByProcessInstanceId(processInstanceId);
                Map<String, Object> routerVariables = processInstance.getRouterVariables();
                Object childVariableList = routerVariables.get("childVariableList");
                if (!BinaryUtils.isEmpty(childVariableList)) {
                    List<ApproveParam> approveParams = JSONObject.parseArray(childVariableList.toString(), ApproveParam.class);
                    for (ApproveParam approveParam : approveParams) {
                        String businessKey = approveParam.getBusinessKey();
                        log.info("########### 处理子流程 businessKey：【{}】", approveParam.getBusinessKey());
                        DiagramApproveRlt approveRlt = diagramApproveRltSvc.getApproveRlt(Long.valueOf(approveParam.getBusinessKey()));
                        List<Long> approveDiagramIds = approveRlt.getDiagramIdList();
                        log.info("############# 子流程终止，修改本地视图状态：approveDiagramIds【{}】", JSONObject.toJSONString(approveDiagramIds));
                        esDiagramSvc.updateFlowStatusByIds(approveDiagramIds, 0);
                        log.info("############# 本地视图状态修改成功，将审批关联表数据修改为正常（终止）：businessKey【{}】", businessKey);
                        diagramApproveRltSvc.changeApproveRltFlowStatus(Long.valueOf(businessKey), 0);
                    }
                } else {
                    log.info("########### 当前任务不包含子流程 processInstanceId：【{}】", processInstanceId);
                }
            }
            if (!StringUtils.isEmpty(request.getRemark())) {
                taskRequest.setRemarks(request.getRemark());
            }
            // 过滤掉已经同意的用户
            taskRequest.setFilterUser(Boolean.TRUE);
            try {
                taskResponse = flowableFeign.completeTask(taskRequest);
            } catch (Exception e) {
                cancelPlan(plan);
                ProcessRequest processRequest = new ProcessRequest();
                processRequest.setBusinessKey(String.valueOf(plan.getId()));
                flowableFeign.deleteProcessInstanceByBusinessId(processRequest);
                // 删除工作台待办已办
                TaskResponse workbenchTask = flowableFeign.getTaskInfoByTaskId(taskId);
                if (workbenchTask != null && !StringUtils.isEmpty(workbenchTask.getProcessInstanceId())) {
                    WorkbenchChargeDone workbenchChargeDone = new WorkbenchChargeDone();
                    workbenchChargeDone.setProcessInstanceId(workbenchTask.getProcessInstanceId());
                    workbenchChargeDoneSvc.deleteByCondition(workbenchChargeDone);
                }
                throw new BusinessException("方案提交审批失败!");
            }

            if (Objects.equals(request.getApproval(), 3)) {
                // 终止方案
                /*if (deliverableTemplate == null || deliverableTemplate.getApprovalType() == null) {
                    cancelPlan(plan);
                }*/
                cancelPlan(plan);
                // 终止流程不再执行后续操作
                return 1L;
            } else {
                // 修改方案中视图状态
                updatePlanDiagramIsFlow(request.getPlanId(), 2);
            }
        } else if (Objects.equals(request.getSign(), Constants.ACTIVE_APPROVAL)) {
            if (StringUtils.isEmpty(request.getTaskId())) {
                throw new BusinessException("任务主键不能为空!");
            }
            if (request.getApproval() == null) {
                throw new BusinessException("审批动作不能为空!");
            }
            if (!Objects.equals(request.getApproval(), 1) && !Objects.equals(request.getApproval(), 2)
                    && !Objects.equals(request.getApproval(), 3)) {
                throw new BusinessException("审批动作参数错误!");
            }

            // 如果位置为空，发驳回通知返回固定的编码，前端作特殊化处理
            if (!Objects.equals(request.getApproval(), 3) && category == null) {

                // 修改方案中视图状态
                updatePlanDiagramIsFlow(plan.getId(), 0);

                // 执行审批
                TaskRequest taskRequestInfo = new TaskRequest();
                taskRequestInfo.setAction(FLOWACTION.REJECT);
                taskRequestInfo.setRemarks("方案发布位置已被删除!");
                taskRequestInfo.setTaskId(request.getTaskId());
                // 过滤掉已经同意的用户
                taskRequestInfo.setFilterUser(Boolean.TRUE);
                TaskResponse unPassTask = flowableFeign.completeTask(taskRequestInfo);

                // 再流程中的方案发布状态是草稿
                plan.setStatus(PlanStatusEnum.draft.name());
                plan.setProcessApproval(false);
                plan.setTaskId(unPassTask.getTaskId());
                planDesignInstanceDao.saveOrUpdate(plan);
                return -2L;
            }

            // 执行审批
            TaskRequest taskRequest = new TaskRequest();
            if (Objects.equals(request.getApproval(), 1)) {
                PlanChapterQuestion question = new PlanChapterQuestion();
                question.setPlanId(request.getPlanId());
                question.setCheckResult(QuestionCheckEnum.PASS.getCode());
                question.setCreatorCode(SysUtil.getCurrentUserInfo().getLoginCode());
                question.setProcessInstanceId(request.getProcessInstanceId());
                question.setTaskDefinitionKey(request.getTaskDefinitionKey());
                // 存在待验证的数量
                Long num = planChapterQuestionService.countQuestion(question);
                if (num != null && num > 0) {
                    throw new BusinessException("存在未验证通过的问题，提交审批失败!");
                }
                taskRequest.setAction(FLOWACTION.ACCETP);
            } else if (Objects.equals(request.getApproval(), 2)) {
                taskRequest.setAction(FLOWACTION.REJECT);
            } else if (Objects.equals(request.getApproval(), 3)) {
                // 若当前方案包含子流程 终止所有子流程
                String processInstanceId = request.getProcessInstanceId();
                PorcessResponse processInstance = flowableFeign.getProcessInstanceByProcessInstanceId(processInstanceId);
                Map<String, Object> routerVariables = processInstance.getRouterVariables();
                Object childVariableList = routerVariables.get("childVariableList");
                if (!BinaryUtils.isEmpty(childVariableList)) {
                    List<ApproveParam> approveParams = JSONObject.parseArray(childVariableList.toString(), ApproveParam.class);
                    for (ApproveParam approveParam : approveParams) {
                        String businessKey = approveParam.getBusinessKey();
                        log.info("########### 处理子流程 businessKey：【{}】", approveParam.getBusinessKey());
                        DiagramApproveRlt approveRlt = diagramApproveRltSvc.getApproveRlt(Long.valueOf(approveParam.getBusinessKey()));
                        List<Long> approveDiagramIds = approveRlt.getDiagramIdList();
                        log.info("############# 子流程终止，修改本地视图状态：approveDiagramIds【{}】", JSONObject.toJSONString(approveDiagramIds));
                        esDiagramSvc.updateFlowStatusByIds(approveDiagramIds, 0);
                        log.info("############# 本地视图状态修改成功，将审批关联表数据修改为正常（终止）：businessKey【{}】", businessKey);
                        diagramApproveRltSvc.changeApproveRltFlowStatus(Long.valueOf(businessKey), 0);
                    }
                } else {
                    log.info("########### 当前任务不包含子流程 processInstanceId：【{}】", processInstanceId);
                }
                taskRequest.setAction(FLOWACTION.CANCEL);
            }
            if (!StringUtils.isEmpty(request.getRemark())) {
                taskRequest.setRemarks(request.getRemark());
            }
            taskRequest.setTaskId(request.getTaskId());
            // 过滤掉已经同意的用户
            taskRequest.setFilterUser(Boolean.TRUE);
            taskResponse = flowableFeign.completeTask(taskRequest);

            // 如果是驳回保存taskId
            if (Objects.equals(request.getApproval(), 2)) {
                // 将方案改为非流程中状态
                processApproval = !processApproval;

                /*if (deliverableTemplate == null || deliverableTemplate.getApprovalType() == null) {*/
                // 修改方案中视图状态
                updatePlanDiagramIsFlow(request.getPlanId(), 0);
                //查方案流程发起人
                PorcessResponse porcessResponse = flowableFeign.getProcessInstanceByProcessInstanceId(request.getProcessInstanceId());
                if (porcessResponse == null || StringUtils.isBlank(porcessResponse.getProcessStartUserId())) {
                    throw new BusinessException("方案驳回流程错误!");
                }
                // 先判断是否已开启流程任务
                TaskResponse taskInfo = flowableFeign.getCurrentUserTask(String.valueOf(plan.getId()), taskResponse.getProcessDefinitionKey(), porcessResponse.getProcessStartUserId());
                if (taskInfo == null || StringUtils.isEmpty(taskInfo.getTaskId())) {
                    throw new BusinessException("方案驳回流程错误!");
                }
                taskId = taskInfo.getTaskId();
                /*}*/
            } else if (Objects.equals(request.getApproval(), 3)) {
                // 终止方案
//                if (deliverableTemplate == null || deliverableTemplate.getApprovalType() == null
//                        || (!Objects.equals(deliverableTemplate.getApprovalType(), 1))) {
//                    cancelPlan(plan);
//                }
                cancelPlan(plan);
                // 终止流程不再执行后续操作
                return 1L;
            }

        }

        if (taskResponse != null) {
            if (!taskResponse.getProcessEnd())  {
                // 再流程中的方案发布状态是草稿，获取最新的方案避免taskId被覆盖
                PlanDesignInstance newPlan = planDesignInstanceDao.getById(request.getPlanId());
                newPlan.setStatus(PlanStatusEnum.draft.name());
                newPlan.setProcessApproval(processApproval);
                /*if (deliverableTemplate == null || deliverableTemplate.getApprovalType() == null
                        || !Objects.equals(deliverableTemplate.getApprovalType(), 2)) {
                    newPlan.setTaskId(taskId);
                }*/
                newPlan.setTaskId(taskId);
                planDesignInstanceDao.saveOrUpdate(newPlan);
            } else {
                /*if (deliverableTemplate == null || deliverableTemplate.getApprovalType() == null) {
                    return passPlan(plan, userInfo);
                }*/
                PorcessResponse porcessResponse = flowableFeign.getProcessInstanceByProcessInstanceId(request.getProcessInstanceId());
                if (porcessResponse != null) {
                    TaskFromWorkflowContext.setContext(new TaskFromWorkflowContextValue(true, porcessResponse.getProcessStartUserId()));
                }
                Long result = passPlan(plan, userInfo, false);
                TaskFromWorkflowContext.release();
                return result;
            }

        }
        return 1L;
    }

    public Long passPlan(PlanDesignInstance plan, UserInfo userInfo, Boolean archReview) {
        // 流程结束删除缓存方案状态
        String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
        iCacheService.delKey(key);
        //判断方案发布位置
        planInstanceServiceExtend.getPlanReleaseDirInfo(plan);
        // 流程结束发布方案和视图
        Long result = publishDiagramAndPlan(plan, userInfo, archReview);
        if (Objects.equals(result, -2L)) {
            return result;
        }

        // 设置方案发布状态
        plan.setStatus(PlanStatusEnum.published.name());
        plan.setDetectionPlanId(result);
        plan.setProcessApproval(false);
        plan.setTaskId("");
        planDesignInstanceDao.saveOrUpdate(plan);
        return result;
    }



    /**
     * 回滚方案
     * @param planDesignInstance 新生成的版本方案
     * @param plan 设计库方案
     * @param archReview 是否架构评审
     */
    private void rollbackPlan(PlanDesignInstance planDesignInstance, PlanDesignInstance plan, Boolean archReview) {
        // 删除方案
        planDesignInstanceDao.deleteById(planDesignInstance.getId());
        // 删除章节
        planChapterInstanceService.deletePlanChapter(planDesignInstance.getId());
        // 2.3 删除模块数据
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("planId", planDesignInstance.getId()));
        chapterContextDao.deleteByQuery(boolQueryBuilder, true);
        // 2.4 删除方案关联视图信息
        planArtifactService.deletePlanArtifact(planDesignInstance.getId());
        // 删除方案关联的文件夹
        dirRelationPlanService.deleteDirRelationPlan(planDesignInstance.getId());

        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        query.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.history.name()));
        Page<PlanDesignInstance> page = planDesignInstanceDao.getSortListByQuery(1, 100, query, "createTime", false);
        if (page != null && !CollectionUtils.isEmpty(page.getData())) {
            List<PlanDesignInstance> data = page.getData();
            PlanDesignInstance planDesign = data.get(0);
            planDesign.setStatus(PlanStatusEnum.published.name());
            planDesignInstanceDao.saveOrUpdate(planDesign);
        }

        PlanDesignInstance newPlan = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, newPlan);
        newPlan.setStatus(PlanStatusEnum.draft.name());
        newPlan.setProcessApproval(false);
        newPlan.setTaskId(null);
        planDesignInstanceDao.saveOrUpdate(newPlan);

        // 发布失败修改视图可编辑状态
        updateDiagramState(plan.getId(), 0);

        // 终止删除问题和批注
        if (!archReview) {
            planChapterQuestionService.deleteQuestionAndAnnotationByPlanId(plan.getId());
        }
    }

    /**
     * 处理历史版本方案
     * @param plan
     * @param userInfo
     */
    private PlanDesignInstance handlerHistoryPlan(PlanDesignInstance plan, UserInfo userInfo) {
        // 1.将所有业务主键一样状态是发布的 方案/章节/数据模块 改为历史版本
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        query.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
        List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(query);
        if (!CollectionUtils.isEmpty(planDesignInstanceList)) {
            List<ChapterInstance> historyChapterList = new ArrayList<>();
            List<ChapterContext> historyContextList = new ArrayList<>();
            planDesignInstanceList.forEach(planInfo -> {
                // 修改方案历史版本
                planInfo.setProcessApproval(false);
                planInfo.setStatus(PlanStatusEnum.history.name());
                planInfo.setModifyTime(ESUtil.getNumberDateTime());
                planInfo.setModifierCode(userInfo.getLoginCode());
                planInfo.setModifierName(userInfo.getUserName());
                // 修改章节历史版本
                List<ChapterInstance> chapterInstanceList = planChapterInstanceService.findChapterInstanceList(planInfo.getId(), Constants.RELEASE);
                if (!CollectionUtils.isEmpty(chapterInstanceList)) {
                    chapterInstanceList.forEach(chapter -> {
                        chapter.setStatus(Constants.HISTORICAL_VERSION);
                        chapter.setModifyTime(ESUtil.getNumberDateTime());
                        chapter.setModifierCode(userInfo.getLoginCode());
                        chapter.setModifierName(userInfo.getUserName());
                    });
                    historyChapterList.addAll(chapterInstanceList);
                }
                //修改模块数据为历史版本
                BoolQueryBuilder contextQuery = QueryBuilders.boolQuery();
                contextQuery.must(QueryBuilders.termQuery("planId", planInfo.getId()));
                contextQuery.must(QueryBuilders.termQuery("status", Constants.RELEASE));
                List<ChapterContext> chapterContextList = chapterContextDao.getListByQuery(contextQuery);
                if (!CollectionUtils.isEmpty(chapterContextList)) {
                    chapterContextList.forEach(context -> {
                        context.setStatus(Constants.HISTORICAL_VERSION);
                    });
                    historyContextList.addAll(chapterContextList);
                }
            });
            // 修改方案
            planDesignInstanceDao.saveOrUpdateBatch(planDesignInstanceList);
            // 修改章节
            planChapterInstanceService.saveOrUpdateBatch(historyChapterList);
            // 修改模块
            chapterContextDao.saveOrUpdateBatch(historyContextList);
        }
        // 2.新增一个新的已发布的 方案/章节/数据模块
        //2.1 新增方案
        PlanDesignInstance planDesignInstance = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, planDesignInstance);
        planDesignInstance.setProcessApproval(false);
        planDesignInstance.setId(ESUtil.getUUID());
        planDesignInstance.setCreateTime(ESUtil.getNumberDateTime());
        planDesignInstance.setModifyTime(ESUtil.getNumberDateTime());
        planDesignInstance.setModifierCode(userInfo.getLoginCode());
        planDesignInstance.setModifierName(userInfo.getUserName());
        planDesignInstance.setStatus(PlanStatusEnum.published.name());
        planDesignInstance.setAssetsType(Constants.ASSETS);
        //如果存在流程且流程提交人非方案创建人，则发布到资产库的方案创建人为发布人
        TaskFromWorkflowContextValue contextValue = TaskFromWorkflowContext.getContext();
        if (contextValue != null && contextValue.getFromWorkflow()) {
            if (!planDesignInstance.getCreatorCode().equals(contextValue.getStartUserLoginCode())) {
                planDesignInstance.setCreatorCode(contextValue.getStartUserLoginCode());
                CSysUser cdt = new CSysUser();
                cdt.setLoginCodeEqual(contextValue.getStartUserLoginCode());
                List<SysUser> sysUserList = userApiSvc.getSysUserByCdt(cdt);
                String userName = contextValue.getStartUserLoginCode();
                if (!CollectionUtils.isEmpty(sysUserList)) {
                    userName = sysUserList.get(0).getUserName();
                }
                planDesignInstance.setCreatorName(userName);
            }
        }
        Long newPlanId = planDesignInstanceDao.saveOrUpdate(planDesignInstance);
        // 2.2 新增章节
        List<ChapterInstance> chapterInstanceList = planChapterInstanceService.findChapterInstanceList(plan.getId(), null);
        if (!CollectionUtils.isEmpty(chapterInstanceList)) {
            Map<Long, Long> map = new HashMap<>();
            chapterInstanceList.forEach(chapterInstance -> {
                long chapterId = ESUtil.getUUID();
                map.put(chapterInstance.getId(), chapterId);
            });

            List<ChapterInstance> newChapterInstanceList = new ArrayList<>();
            List<ChapterContext> newChapterContextList = new ArrayList<>();
            List<PlanArtifact> newPlanArtifactList = new ArrayList<>();
            chapterInstanceList.forEach(chapterInstance -> {
                ChapterInstance newChapterInstance = new ChapterInstance();
                BeanUtils.copyProperties(chapterInstance, newChapterInstance);
                newChapterInstance.setId(map.get(chapterInstance.getId()));
                newChapterInstance.setPlanId(newPlanId);
                newChapterInstance.setStatus(Constants.RELEASE);
                newChapterInstance.setCreateTime(ESUtil.getNumberDateTime());
                newChapterInstance.setModifyTime(ESUtil.getNumberDateTime());
                newChapterInstance.setModifierCode(userInfo.getLoginCode());
                newChapterInstance.setModifierName(userInfo.getUserName());
                if (!Objects.equals(chapterInstance.getParentId(), 0L)) {
                    newChapterInstance.setParentId(map.get(chapterInstance.getParentId()));
                }
                newChapterInstanceList.add(newChapterInstance);

                BoolQueryBuilder contextQuery = QueryBuilders.boolQuery();
                contextQuery.must(QueryBuilders.termQuery("id", chapterInstance.getId()));
                List<ChapterContext> chapterContextList = chapterContextDao.getListByQuery(contextQuery);
                if (!CollectionUtils.isEmpty(chapterContextList)) {
                    chapterContextList.forEach(context -> {
                        ChapterContext newChapterContext = new ChapterContext();
                        BeanUtils.copyProperties(context, newChapterContext);
                        newChapterContext.setId(newChapterInstance.getId());
                        newChapterContext.setPlanId(newPlanId);
                        newChapterContext.setStatus(Constants.RELEASE);
                        newChapterContextList.add(newChapterContext);
                    });
                }

                // 复制方案关联的视图
                PlanArtifact planArtifact = new PlanArtifact();
                planArtifact.setPlanId(plan.getId());
                planArtifact.setChapterId(chapterInstance.getId());
                planArtifact.setStatus(1);
                List<PlanArtifact> planArtifactList = planArtifactService.findPlanArtifactList(planArtifact);
                if (!CollectionUtils.isEmpty(planArtifactList)) {
                    planArtifactList.forEach(planArtifactInfo -> {
                        PlanArtifact newPlanArtifact = new PlanArtifact();
                        BeanUtils.copyProperties(planArtifactInfo, newPlanArtifact);
                        newPlanArtifact.setId(ESUtil.getUUID());
                        newPlanArtifact.setPlanId(newPlanId);
                        newPlanArtifact.setChapterId(newChapterInstance.getId());
                        newPlanArtifact.setCreateTime(ESUtil.getNumberDateTime());
                        newPlanArtifact.setModifyTime(ESUtil.getNumberDateTime());
                        newPlanArtifact.setModifierCode(userInfo.getLoginCode());
                        newPlanArtifact.setModifierName(userInfo.getUserName());
                        newPlanArtifactList.add(newPlanArtifact);
                    });
                }
            });
            planChapterInstanceService.saveOrUpdateBatch(newChapterInstanceList);
            // 2.3 新增模块数据
            chapterContextDao.saveOrUpdateBatch(newChapterContextList);
            // 2.4 新增方案关联视图信息
            planArtifactService.savePlanArtifact(newPlanArtifactList);
            // 2.5 新增方案、章节、内容块相关的批注列表
            // 2.5.1 查询当前方案+流程的批注列表
            BoolQueryBuilder annotationQuery = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("delFlag", false))
                    .must(QueryBuilders.termQuery("planId", plan.getId()))
                    .must(QueryBuilders.termQuery("taskDefinitionKey.keyword", plan.getProcessInstanceId()));

            FieldSortBuilder sortBuilder = new FieldSortBuilder("createTime").order(SortOrder.DESC);
            List<PlanModuleAnnotationEntity> annotationEntities = planModuleAnnotationDao.getSortListByQuery(1, 3000, annotationQuery,
                    ListUtil.of(sortBuilder)).getData();
            // 2.5.2 映射批注id 批注原id与新批注id映射关系 用于保存问题时,问题的annotationId关联新生成的批注id
            Map<Long, Long> annotationIdMap = new HashMap<>();
            for (PlanModuleAnnotationEntity annotationEntity : annotationEntities) {
                Long oldId = annotationEntity.getId();
                Long newId = ESUtil.getUUID();
                annotationEntity.setId(newId);
                annotationEntity.setPlanId(newPlanId);
                annotationEntity.setPlanChapterId(map.get(annotationEntity.getPlanChapterId()));
                annotationIdMap.put(oldId, newId);
            }
            // 2.5.3 保存方案发布后的批注列表
            planModuleAnnotationDao.saveOrUpdateBatch(annotationEntities);

            // 2.6 新增方案、章节、内容块相关的问题列表
            // 2.6.1 查询当前方案+流程的问题列表
            BoolQueryBuilder questionQuery = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("planId", plan.getId()))
                    .must(QueryBuilders.termQuery("processInstanceId.keyword", plan.getProcessInstanceId()));
            List<PlanChapterQuestion> questions = planChapterQuestionDao.getSortListByQuery(1, 3000, questionQuery, "createTime", false).getData();
            for (PlanChapterQuestion question : questions) {
                question.setId(ESUtil.getUUID());
                question.setPlanId(newPlanId);
                question.setPlanChapterId(map.get(question.getPlanChapterId()));
                question.setAnnotationId(annotationIdMap.get(question.getAnnotationId()));
            }
            planChapterQuestionDao.saveOrUpdateBatch(questions);
        }
        return planDesignInstance;
    }

    private Long handlerPublishPlan(PlanDesignInstance plan) {
        EamCategory category = categorySvc.getById(plan.getAssetsDirId(), LibType.DESIGN);
        if (category == null) {
            //throw new BinaryException("发布的资产文件夹已删除");
            return -2L;
        }
        handleDirRelationPlan(plan.getAssetsDirId(), plan);
        return null;
    }

    private void handlerPublishDiagram(List<ChapterContext> contextList, PlanDesignInstance plan) {
        Map<String, ESDiagram> eaDiagramMap = new HashMap<>();
        // 发布制品
        for (ChapterContext context : contextList) {
            if(context == null || CollectionUtils.isEmpty(context.getModuleList())){
                continue;
            }
            List<ContextModule> moduleList = context.getModuleList();
            for (ContextModule module : moduleList) {
                if (!ChapterDataTypeEnum.PRODUCT.getDataType().equals(module.getModuleDefinition().getType())) {
                    continue;
                }
                String productRequired = module.getModuleDefinition().getProductRequired();
                JSONObject jsonObject = JSONObject.parseObject(module.getData());
                if (Objects.equals(productRequired, "1")) {
                    if (jsonObject == null || StringUtils.isEmpty(jsonObject.getString("diagramId"))
                            || jsonObject.getInteger("isOpen") == null) {
                        throw new BusinessException("视图信息错误，提交审批失败!");
                    }
                } else {
                    if (jsonObject == null || StringUtils.isEmpty(jsonObject.getString("diagramId"))
                            || jsonObject.getInteger("isOpen") == null) {
                        continue;
                    }
                }
                Integer dirType = jsonObject.getInteger("dirType");
                Integer isOpen = jsonObject.getInteger("isOpen");
                EamDiagramRelationSys sys = eamDiagramRelationSysService.getEamDiagramRelationSys(jsonObject.getString("diagramId"));
                if (Objects.equals(isOpen, 0)) {
                    ESDiagram esDiagram = eaDiagramMap.get(jsonObject.getString("diagramId"));
                    if (esDiagram == null) {
                        Long dirId = jsonObject.getLongValue("assetsDirId");
//                        if (sys != null && !StringUtils.isEmpty(sys.getEsSysId())) {
//                            EamCategory finalDiagramDir = categorySvc.selectByCiCode(null, sys.getEsSysId(), null, LibType.DESIGN);
//                            dirId = finalDiagramDir.getId();
//                        }
                        // 发布视图
                        String publishId = publishDiagram(jsonObject.getString("diagramId"), dirId);
                        esDiagram = diagramApiClient.getEsDiagram(publishId, 1);
                    }
                    if (esDiagram == null) {
                        throw new BusinessException("关联视图已经被删除!");
                    }
                    eaDiagramMap.put(jsonObject.getString("diagramId"), esDiagram);
                    // 存储视图和版本
                    Integer version = handlePlanArtifact(plan.getId(), context.getId(), module.getId(), jsonObject.getString("diagramId"), esDiagram, isOpen);
                    jsonObject.put("diagramId", esDiagram.getDEnergy());
                    jsonObject.put("isOpen", esDiagram.getIsOpen());
                    jsonObject.put("releaseVersion", version);
                    module.setData(jsonObject.toJSONString());
                } else {
                    ESDiagram diagram = eaDiagramMap.get(jsonObject.getString("diagramId"));
                    if (diagram == null){
                        diagram = diagramApiClient.getEsDiagram(jsonObject.getString("diagramId"), 1);
                        if (diagram == null) {
                            throw new BusinessException("关联视图已经被删除!");
                        }
                    }
                    eaDiagramMap.put(jsonObject.getString("diagramId"), diagram);
                    // 存储视图和版本
                    Integer version = handlePlanArtifact(plan.getId(), context.getId(), module.getId(), jsonObject.getString("diagramId"), diagram, isOpen);
                    jsonObject.put("diagramId", diagram.getDEnergy());
                    jsonObject.put("isOpen", diagram.getIsOpen());
                    jsonObject.put("releaseVersion", version);
                    module.setData(jsonObject.toJSONString());
                }
            }
            context.setModuleList(moduleList);
        }
        chapterContextDao.saveOrUpdateBatch(contextList);
    }

    private String publishDiagram(String diagramId, Long dirId) {
        ESDiagram privateDiagram = diagramApiClient.getEsDiagram(diagramId, 0);
        Long privateDirId = privateDiagram.getDirId();
        EamCategory privateCategory = categorySvc.getById(privateDirId, LibType.PRIVATE);
        EamCategory category = categorySvc.getById(dirId, LibType.DESIGN);
        String releaseDiagramId = "";
        if (BinaryUtils.isEmpty(category)) {
            throw new ServerException("视图ID["+diagramId+"]所选的发布位置["+dirId+"]异常");
        }
        if (BinaryUtils.isEmpty(privateCategory)) {
            // 根目录异常
            releaseDiagramId = generalPushSvc.publishDiagram(diagramId, null, dirId, null, Boolean.FALSE, true);
        } else {
            if (privateCategory.getType() != 5) {
                // 普通视图发布
                releaseDiagramId = generalPushSvc.publishDiagram(diagramId, null, dirId, null, Boolean.FALSE, true);
            } else {
                // 模型视图发布
                flowModelMergeSvc.push(new ArrayList<>(), diagramId, null, dirId);
                ESDiagram esDiagram = diagramApiClient.getEsDiagram(diagramId, 0);
                releaseDiagramId =  esDiagram.getReleaseDiagramId();
            }
        }
        // 更新本地视图流程状态
        Long privateId = privateDiagram.getId();
        esDiagramSvc.updateFlowStatusByIds(Collections.singletonList(privateId), 0);
        return releaseDiagramId;
    }

    private Integer handlePlanArtifact(Long planId, Long chapterId, Long moduleId, String diagramId, ESDiagram esDiagram, Integer isOpen) {
        PlanArtifact planArtifact = new PlanArtifact();
        planArtifact.setPlanId(planId);
        planArtifact.setChapterId(chapterId);
        planArtifact.setModuleId(moduleId);
        planArtifact.setDiagramId(diagramId);
        // 视图是未发布的图控制版本
        Integer result = null;
        if (Objects.equals(isOpen, 0)) {
            planArtifact.setVersion(esDiagram.getReleaseVersion());
            result = esDiagram.getReleaseVersion();
        } else {
            List<PlanArtifact> planArtifactList = planArtifactService.findPlanArtifactList(planArtifact);
            if (!CollectionUtils.isEmpty(planArtifactList)) {
                PlanArtifact plan = planArtifactList.get(0);
                result = plan.getVersion();
            }
        }
        planArtifact.setReleaseDiagramId(esDiagram.getDEnergy());
        planArtifactService.updatePlanArtifact(planArtifact);
        return result;
    }

    /**
     * 验证章节内容必填
     */
    private Map<String, Object> handlerChapter(List<ChapterContext> contextList) {
        if (CollectionUtils.isEmpty(contextList)) {
            throw new BusinessException("获取方案章节内容错误!");
        }

        // 存在问题的章节模块
        List<ProblemChapterVO> problemChapterList = new ArrayList<>();
        // 存在问题的制品模块
        List<ProblemChapterVO> problemDiagramList = new ArrayList<>();
        // 存在问题的模块数量
        AtomicInteger moduleNum = new AtomicInteger(0);
        // 存在问题的模块数量
        AtomicInteger diagramNum = new AtomicInteger(0);
        // 获取视图列表，查询是否存在被删除的视图
        List<String> diagramIds = new ArrayList<>();
        // 判断所有章节内容必填项是否都已填写
        for(ChapterContext context : contextList) {
            if (context != null && !CollectionUtils.isEmpty(context.getModuleList())) {
                // 问题模块
                List<ProblemModuleVO> problemModuleList = new ArrayList<>();
                // 问题制品
                List<ProblemDiagramVO> problemDiagrams = new ArrayList<>();
                // 方案章节信息
                ChapterInstance planChapterInstance = planChapterInstanceService.getPlanChapterInstance(context.getId());
                ProblemChapterVO chapterModule = new ProblemChapterVO();
                chapterModule.setPlanId(context.getPlanId());
                chapterModule.setChapterId(context.getId());
                if (planChapterInstance != null) {
                    String name = String.format("%s %s", planChapterInstance.getSerialNum(), planChapterInstance.getName());
                    chapterModule.setSerialNum(planChapterInstance.getSerialNum());
                    chapterModule.setChapterName(name);
                    chapterModule.setLevel(planChapterInstance.getLevel());
                    chapterModule.setOrderId(planChapterInstance.getOrderId());
                }
                ProblemChapterVO chapterDiagram = new ProblemChapterVO();
                BeanUtils.copyProperties(chapterModule, chapterDiagram);
                List<ContextModule> moduleList = context.getModuleList();
                moduleList.forEach(module -> {
                    ProblemModuleVO problemModuleVO = new ProblemModuleVO();
                    problemModuleVO.setModuleId(module.getId());
                    PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();
                    JSONObject jsonObject = JSONObject.parseObject(module.getData());
                    if (ChapterDataTypeEnum.PRODUCT.getDataType().equals(moduleDefinition.getType())) {
                        if (Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getProductRequired())) {
                            problemModuleVO.setModuleName(moduleDefinition.getProductName());
                            if (jsonObject.size() == 0) {
                                problemModuleList.add(problemModuleVO);
                            } else if (jsonObject.containsKey(Constants.DATA_SIGN) && StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN))) {
                                problemModuleList.add(problemModuleVO);
                            } else {
                                Set<Object> valueSet = new HashSet<>();
                                jsonObject.forEach((key, value) -> {
                                    if (!StringUtils.isEmpty(String.valueOf(value))) {
                                        valueSet.add(value);
                                    }
                                });
                                if (CollectionUtils.isEmpty(valueSet)) {
                                    problemModuleList.add(problemModuleVO);
                                }
                            }
                        }
                        if (jsonObject.size() > 0 && !StringUtils.isEmpty(jsonObject.getString("diagramId"))){
                            diagramIds.add(jsonObject.getString("diagramId"));

                            DiagramParamDto param = new DiagramParamDto();
                            param.setDiagramIds(Collections.singletonList(jsonObject.getString("diagramId")));
                            param.setDomainId(1L);
                            param.setOwnerCode(SysUtil.getCurrentUserInfo().getLoginCode());
                            if (jsonObject.getInteger("isOpen") != null) {
                                param.setIsOpens(Collections.singletonList(jsonObject.getInteger("isOpen")));
                            }
                            if (jsonObject.getInteger("dirType") != null) {
                                param.setDirTypes(Collections.singletonList(jsonObject.getInteger("dirType")));
                            } else {
                                Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(jsonObject.getString("diagramId"));
                                if (diagramId == null) {
                                    throw new BusinessException("获取视图信息错误!");
                                }
                                ESDiagram diagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                if (diagram != null) {
                                    // 缩略图
                                    String icon1 = diagram.getIcon1();
                                    if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                        icon1 = httpResouceUrl + icon1;
                                        diagram.setIcon1(icon1);
                                    }
                                }
                                param.setDirTypes(Collections.singletonList(diagram.getDirType()));
                            }
                            try {
                                PushParams params = new PushParams();
                                BeanUtils.copyProperties(param, params);
                                ReleaseValidResponse releaseValidResponse = pushFacadeService.checkCjDiagram(params);
                                ReleaseValidResponse.ValidType validType = releaseValidResponse.getValidType();
                                if (validType != null && ReleaseValidResponse.ValidType.CI_DATA.equals(validType)) {
                                    Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(jsonObject.getString("diagramId"));
                                    if (diagramId == null) {
                                        throw new BusinessException("获取视图信息错误!");
                                    }
                                    ESDiagram esDiagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                    if (esDiagram != null) {
                                        // 缩略图
                                        String icon1 = esDiagram.getIcon1();
                                        if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                            icon1 = httpResouceUrl + icon1;
                                            esDiagram.setIcon1(icon1);
                                        }
                                    }
                                    if (esDiagram != null) {
                                        ProblemDiagramVO problemDiagram = new ProblemDiagramVO();
                                        problemDiagram.setModuleId(module.getId());
                                        problemDiagram.setEsDiagram(esDiagram);
                                        problemDiagrams.add(problemDiagram);
                                    }
                                }
                            } catch (Exception e) {
                                try {
                                    Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(jsonObject.getString("diagramId"));
                                    if (diagramId == null) {
                                        throw new BusinessException("获取视图信息错误!");
                                    }
                                    ESDiagram esDiagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                    if (esDiagram != null) {
                                        // 缩略图
                                        String icon1 = esDiagram.getIcon1();
                                        if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                            icon1 = httpResouceUrl + icon1;
                                            esDiagram.setIcon1(icon1);
                                        }
                                    }
                                    if (esDiagram == null) {
                                        throw new BusinessException("视图已经被删除，请进入编辑页面重新选择！");
                                    } else {
                                        throw new BusinessException("校验视图错误!");
                                    }
                                } catch (Exception ex) {
                                    throw new BusinessException("视图已经被删除，请进入编辑页面重新选择！");
                                }
                            }
                        }
                    } else if (ChapterDataTypeEnum.RICH_TEXT.getDataType().equals(moduleDefinition.getType()) &&
                            Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getRichTextRequired()) &&
                            (jsonObject.size() == 0 || jsonObject.containsKey(Constants.DATA_SIGN) && StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN)))) {
                        problemModuleVO.setModuleName(moduleDefinition.getRichTextName());
                        problemModuleList.add(problemModuleVO);
                    } else if (ChapterDataTypeEnum.DATA_TABLE.getDataType().equals(moduleDefinition.getType()) &&
                            Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getDataTableRequired()) && !CollectionUtils.isEmpty(moduleDefinition.getDataTableContent())){
                        problemModuleVO.setModuleName(moduleDefinition.getDataTableName());
                        if (jsonObject.size() == 0 || jsonObject.containsKey(Constants.DATA_SIGN) && StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN))) {
                            problemModuleList.add(problemModuleVO);
                        } else {
                            Map<String, Boolean> map = moduleDefinition.getDataTableContent().stream().collect(Collectors.toMap(RowTableContentVo::getName, RowTableContentVo::getRequired));
                            JSONArray jsonArray = JSONArray.parseArray(jsonObject.getString(Constants.DATA_SIGN));
                            boolean status = false;
                            for(int i = 0; i< jsonArray.size(); i++){
                                JSONObject tableData = JSONObject.parseObject(jsonArray.get(i).toString());
                                Set<String> dataTableKey = tableData.keySet();
                                for (String key : dataTableKey) {
                                    if (map.get(key) != null && map.get(key) && StringUtils.isEmpty(tableData.getString(key))) {
                                        status = true;
                                        break;
                                    }
                                }
                            }
                            if (status) {
                                problemModuleList.add(problemModuleVO);
                            }
                        }
                    } else if (ChapterDataTypeEnum.APPENDIX.getDataType().equals(moduleDefinition.getType()) &&
                            Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getAppendixRequired())) {
                        if (jsonObject.size() == 0 || !jsonObject.containsKey(Constants.DATA_SIGN)) {
                            problemModuleVO.setModuleName(moduleDefinition.getAppendixName());
                            problemModuleList.add(problemModuleVO);
                        }
                        if (jsonObject.containsKey(Constants.DATA_SIGN) && (StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN))
                                || CollectionUtils.isEmpty(JSONArray.parseArray(jsonObject.getString(Constants.DATA_SIGN))))) {
                            problemModuleVO.setModuleName(moduleDefinition.getAppendixName());
                            problemModuleList.add(problemModuleVO);
                        }
                    }
                });
                if (!CollectionUtils.isEmpty(problemModuleList)) {
                    chapterModule.setProblemModuleList(problemModuleList);
                    problemChapterList.add(chapterModule);
                    moduleNum.getAndAdd(problemModuleList.size());
                }
                if (!CollectionUtils.isEmpty(problemDiagrams)) {
                    chapterDiagram.setProblemDiagramList(problemDiagrams);
                    problemDiagramList.add(chapterDiagram);
                    diagramNum.getAndAdd(problemDiagrams.size());
                }
            }

        }
        if (!CollectionUtils.isEmpty(problemChapterList)) {
            problemChapterList = chapterSort(problemChapterList);
        }
        if (!CollectionUtils.isEmpty(problemDiagramList)) {
            problemDiagramList = chapterSort(problemDiagramList);
        }
        // 先判断视图是否被删除验证
        if (!CollectionUtils.isEmpty(diagramIds)) {
            List<ESDiagram> diagramList = diagramApiClient.queryDBDiagramInfoByIds(diagramIds.toArray(new String[0]));
            if (CollectionUtils.isEmpty(diagramList) || diagramIds.size() != diagramList.size()) {
                throw new BusinessException("视图已经被删除，请进入编辑页面重新选择！");
            }
        }

        if (!CollectionUtils.isEmpty(problemChapterList) || !CollectionUtils.isEmpty(problemDiagramList)) {
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("result", false);
            resultMap.put("problemChapter", problemChapterList);
            resultMap.put("problemDiagram", problemDiagramList);
            resultMap.put("moduleNum", moduleNum);
            resultMap.put("diagramNum", diagramNum);
            return resultMap;
        }
        return Collections.emptyMap();
    }

    /**
     * 验证章节内容必填
     */
    private Map<String, Object> handlerChapterNew(List<ChapterContext> contextList) {
        if (CollectionUtils.isEmpty(contextList)) {
            throw new BusinessException("获取方案章节内容错误!");
        }

        // 存在问题的章节模块
        List<ProblemChapterVO> problemChapterList = new ArrayList<>();
        // 存在问题的制品模块
        List<ProblemChapterVO> problemDiagramList = new ArrayList<>();
        // 存在问题的模块数量
        AtomicInteger moduleNum = new AtomicInteger(0);
        // 存在问题的模块数量
        AtomicInteger diagramNum = new AtomicInteger(0);
        // 判断所有章节内容必填项是否都已填写
        for(ChapterContext context : contextList) {
            if (context != null && !CollectionUtils.isEmpty(context.getModuleList())) {
                // 问题模块
                List<ProblemModuleVO> problemModuleList = new ArrayList<>();
                // 问题制品
                List<ProblemDiagramVO> problemDiagrams = new ArrayList<>();
                // 方案章节信息
                ChapterInstance planChapterInstance = planChapterInstanceService.getPlanChapterInstance(context.getId());
                ProblemChapterVO chapterModule = new ProblemChapterVO();
                chapterModule.setPlanId(context.getPlanId());
                chapterModule.setChapterId(context.getId());
                if (planChapterInstance != null) {
                    String name = String.format("%s %s", planChapterInstance.getSerialNum(), planChapterInstance.getName());
                    chapterModule.setSerialNum(planChapterInstance.getSerialNum());
                    chapterModule.setChapterName(name);
                    chapterModule.setLevel(planChapterInstance.getLevel());
                    chapterModule.setOrderId(planChapterInstance.getOrderId());
                }
                ProblemChapterVO chapterDiagram = new ProblemChapterVO();
                BeanUtils.copyProperties(chapterModule, chapterDiagram);
                List<ContextModule> moduleList = context.getModuleList();
                moduleList.forEach(module -> {
                    ProblemModuleVO problemModuleVO = new ProblemModuleVO();
                    problemModuleVO.setModuleId(module.getId());
                    PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();
                    JSONObject jsonObject = JSONObject.parseObject(module.getData());
                    if (ChapterDataTypeEnum.PRODUCT.getDataType().equals(moduleDefinition.getType())) {
                        if (Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getProductRequired())) {
                            problemModuleVO.setModuleName(moduleDefinition.getProductName());
                            if (jsonObject.size() == 0) {
                                problemModuleList.add(problemModuleVO);
                            } else if (jsonObject.containsKey(Constants.DATA_SIGN) && StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN))) {
                                problemModuleList.add(problemModuleVO);
                            } else {
                                Set<Object> valueSet = new HashSet<>();
                                jsonObject.forEach((key, value) -> {
                                    if (!StringUtils.isEmpty(String.valueOf(value))) {
                                        valueSet.add(value);
                                    }
                                });
                                if (CollectionUtils.isEmpty(valueSet)) {
                                    problemModuleList.add(problemModuleVO);
                                }
                            }
                        }
                        if (jsonObject.size() > 0 && !StringUtils.isEmpty(jsonObject.getString("diagramId"))){
                           /* DiagramParamDto param = new DiagramParamDto();
                            param.setDiagramIds(Collections.singletonList(jsonObject.getString("diagramId")));
                            param.setDomainId(1L);
                            param.setOwnerCode(SysUtil.getCurrentUserInfo().getLoginCode());
                            if (jsonObject.getInteger("isOpen") != null) {
                                param.setIsOpens(Collections.singletonList(jsonObject.getInteger("isOpen")));
                            }
                            if (jsonObject.getInteger("dirType") != null) {
                                param.setDirTypes(Collections.singletonList(jsonObject.getInteger("dirType")));
                            } else {
                                Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(jsonObject.getString("diagramId"));
                                if (diagramId == null) {
                                    throw new BusinessException("获取视图信息错误!");
                                }
                                ESDiagram diagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                if (diagram != null) {
                                    // 缩略图
                                    String icon1 = diagram.getIcon1();
                                    if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                        icon1 = httpResouceUrl + icon1;
                                        diagram.setIcon1(icon1);
                                    }
                                }
                                param.setDirTypes(Collections.singletonList(diagram.getDirType()));
                            }*/
                            List<String> diagramIds = new ArrayList<>(1);
                            diagramIds.add(jsonObject.getString("diagramId"));
                            // 替换新校验接口
                            Map<Integer, Object> diagramMap = generalPushSvc.pushCkeck(new ArrayList<>(), diagramIds);
                            if (diagramMap != null) {
                                Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(jsonObject.getString("diagramId"));
                                if (diagramId == null) {
                                    throw new BusinessException("获取视图信息错误!");
                                }
                                ESDiagram esDiagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                if (esDiagram != null) {
                                    // 缩略图
                                    String icon1 = esDiagram.getIcon1();
                                    if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                        icon1 = httpResouceUrl + icon1;
                                        esDiagram.setIcon1(icon1);
                                    }
                                }

                                for (Integer checkType : diagramMap.keySet()) {
                                    ProblemDiagramVO problemDiagram = new ProblemDiagramVO();
                                    problemDiagram.setModuleId(module.getId());
                                    problemDiagram.setEsDiagram(esDiagram);
                                    if (checkType == ConflictEnum.PRIMARY_KEY_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("主键冲突");
                                    } else if (checkType == ConflictEnum.REQUIRED_FIELD_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("必填项未填写!");
                                    } else if (checkType == ConflictEnum.DIAGRAM_VERSION_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("视图版本冲突!");
                                    } else if (checkType == ConflictEnum.PRODUCT_NUM_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("制品数量冲突!");
                                    } else if (checkType == ConflictEnum.MODEL_DIAGRAM_LOCATION_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("模型视图所在的仓库目录存在!");
                                    } else if (checkType == ConflictEnum.MODEL_HIERARCHY_COMPLETE_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("模型树配置完整性冲突!");
                                    } else if (checkType == ConflictEnum.LOCATION_RIGTH_CHECK.getConflictType()) {
                                        problemDiagram.setDiagramProblemDesc("视图发布位置异常!");
                                    }
                                    problemDiagrams.add(problemDiagram);
                                }
                            }
                        }
                    } else if (ChapterDataTypeEnum.RICH_TEXT.getDataType().equals(moduleDefinition.getType()) &&
                            Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getRichTextRequired()) &&
                            (jsonObject.size() == 0 || jsonObject.containsKey(Constants.DATA_SIGN) && StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN)))) {
                        problemModuleVO.setModuleName(moduleDefinition.getRichTextName());
                        problemModuleList.add(problemModuleVO);
                    } else if (ChapterDataTypeEnum.DATA_TABLE.getDataType().equals(moduleDefinition.getType()) && Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getDataTableRequired())){
                        List<RowTableContentVo> dataTableContent = new ArrayList<>();
                        if ((Objects.equals(moduleDefinition.getDataTableForm(), 1) || Objects.equals(moduleDefinition.getDataTableForm(), 2))
                                && !CollectionUtils.isEmpty(moduleDefinition.getDataTableContent())) {
                            dataTableContent = moduleDefinition.getDataTableContent();
                        } else if (Objects.equals(moduleDefinition.getDataTableForm(), 3)) {
                            dataTableContent = moduleDefinition.getMatrixRow();
                        }
                        problemModuleVO.setModuleName(moduleDefinition.getDataTableName());
                        if (jsonObject.size() == 0 || jsonObject.containsKey(Constants.DATA_SIGN) && StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN))) {
                            problemModuleList.add(problemModuleVO);
                        } else {
                            if (Objects.equals(moduleDefinition.getDataTableForm(), 3) && Objects.equals(moduleDefinition.getMatrixConfig(), 2)) {
                                List<RowTableContentVo> matrixColContent = moduleDefinition.getMatrixCol();
                                List<String> matrixNameList = matrixColContent.stream().map(content -> content.getName()).collect(Collectors.toList());
                                Map<String, Boolean> map = matrixColContent.stream().collect(Collectors.toMap(RowTableContentVo::getName, RowTableContentVo::getRequired));

                                List<RowTableContentVo> matrixRowContent = moduleDefinition.getMatrixRow();
                                List<String> matrixRowNameList = matrixRowContent.stream().map(content -> content.getName()).collect(Collectors.toList());

                                JSONArray jsonArray = JSONArray.parseArray(jsonObject.getString(Constants.DATA_SIGN));
                                a: for (int i = 0; i < jsonArray.size(); i++) {
                                    String tableName = matrixNameList.get(i);
                                    Boolean required = map.get(tableName);
                                    if (!required) {
                                        continue;
                                    }
                                    JSONObject tableData = JSONObject.parseObject(jsonArray.get(i).toString());
                                    for (String matrixRow : matrixRowNameList) {
                                        String content = tableData.getString(matrixRow);
                                        if (StringUtils.isEmpty(content)) {
                                            problemModuleList.add(problemModuleVO);
                                            break a;
                                        }
                                    }

                                }
                            } else {
                                Map<String, Boolean> map = dataTableContent.stream().collect(Collectors.toMap(RowTableContentVo::getName, RowTableContentVo::getRequired));
                                JSONArray jsonArray = JSONArray.parseArray(jsonObject.getString(Constants.DATA_SIGN));
                                a: for (int i = 0; i < jsonArray.size(); i++) {
                                    Collection<Boolean> values = map.values();
                                    JSONObject json = (JSONObject) jsonArray.get(i);
                                    if (values.contains(true) && json.size() <= 0) {
                                        problemModuleList.add(problemModuleVO);
                                        break;
                                    }
                                    List<String> definitionKeys = new ArrayList<>(map.keySet());
                                    JSONObject tableData = JSONObject.parseObject(jsonArray.get(i).toString());

                                    Set<String> dataTableKey = tableData.keySet();
                                    List<String> planDefinitionKeys = new ArrayList<>(dataTableKey);
                                    for (String key : dataTableKey) {
                                        if (map.get(key) != null && map.get(key) && StringUtils.isEmpty(tableData.getString(key))) {
                                            problemModuleList.add(problemModuleVO);
                                            break a;
                                        }
                                    }

                                    if (!CollectionUtils.isEmpty(definitionKeys) && !CollectionUtils.isEmpty(planDefinitionKeys)) {
                                        definitionKeys.removeAll(planDefinitionKeys);
                                        if (!CollectionUtils.isEmpty(definitionKeys)) {
                                            for (String definitionKey : definitionKeys) {
                                                if (map.get(definitionKey) != null && map.get(definitionKey)) {
                                                    problemModuleList.add(problemModuleVO);
                                                    break a;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    } else if (ChapterDataTypeEnum.APPENDIX.getDataType().equals(moduleDefinition.getType()) &&
                            Constants.TEMPLATE_CHAPTER_REQUIRED.equals(moduleDefinition.getAppendixRequired())) {
                        if (jsonObject.size() == 0 || !jsonObject.containsKey(Constants.DATA_SIGN)) {
                            problemModuleVO.setModuleName(moduleDefinition.getAppendixName());
                            problemModuleList.add(problemModuleVO);
                        }
                        if (jsonObject.containsKey(Constants.DATA_SIGN) && (StringUtils.isEmpty(jsonObject.getString(Constants.DATA_SIGN))
                                || CollectionUtils.isEmpty(JSONArray.parseArray(jsonObject.getString(Constants.DATA_SIGN))))) {
                            problemModuleVO.setModuleName(moduleDefinition.getAppendixName());
                            problemModuleList.add(problemModuleVO);
                        }
                    }
                });
                if (!CollectionUtils.isEmpty(problemModuleList)) {
                    chapterModule.setProblemModuleList(problemModuleList);
                    problemChapterList.add(chapterModule);
                    moduleNum.getAndAdd(problemModuleList.size());
                }
                if (!CollectionUtils.isEmpty(problemDiagrams)) {
                    chapterDiagram.setProblemDiagramList(problemDiagrams);
                    problemDiagramList.add(chapterDiagram);
                    diagramNum.getAndAdd(problemDiagrams.size());
                }
            }

        }
        if (!CollectionUtils.isEmpty(problemChapterList)) {
            problemChapterList = chapterSort(problemChapterList);
        }
        if (!CollectionUtils.isEmpty(problemDiagramList)) {
            problemDiagramList = chapterSort(problemDiagramList);
        }
        if (!CollectionUtils.isEmpty(problemChapterList) || !CollectionUtils.isEmpty(problemDiagramList)) {
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("result", false);
            resultMap.put("problemChapter", problemChapterList);
            resultMap.put("problemDiagram", problemDiagramList);
            resultMap.put("moduleNum", moduleNum);
            resultMap.put("diagramNum", diagramNum);
            return resultMap;
        }
        return Collections.emptyMap();
        // 获取视图列表
    }

    private List<ProblemChapterVO> chapterSort(List<ProblemChapterVO> chapterList) {
        Map<String, List<ProblemChapterVO>> problemChapterMap = chapterList.stream().collect(Collectors.groupingBy(chapter -> chapter.getSerialNum().substring(0, 1)));
        List<String> serialNumList = problemChapterMap.keySet().stream().sorted().collect(Collectors.toList());
        List<ProblemChapterVO> newProblemChapterList = new ArrayList<>();
        for (String serialNum : serialNumList) {
            List<ProblemChapterVO> problemChapterList = problemChapterMap.get(serialNum);
            ProblemChapterVO problemChapterVO = problemChapterList.stream().max(Comparator.comparing(x -> x.getLevel())).orElse(problemChapterList.get(0));
            Integer maxLevel = problemChapterVO.getLevel();
            Collections.sort(problemChapterList, (o1, o2) -> {
                String serialNum1 = o1.getSerialNum().replaceAll("\\.", "");
                String serialNum2 = o2.getSerialNum().replaceAll("\\.", "");
                int num1 = maxLevel - (serialNum1.length());
                int num2 = maxLevel - (serialNum2.length());
                int serialNumValue1 = Integer.valueOf(serialNum1);
                int serialNumValue2 = Integer.valueOf(serialNum2);
                if (num1 > 0) {
                    for (int i = 0; i < num1; i++) {
                        serialNumValue1 = serialNumValue1 * 10;
                    }
                }
                if (num2 > 0) {
                    for (int i = 0; i < num2; i++) {
                        serialNumValue2 = serialNumValue2 * 10;
                    }
                }
                return serialNumValue1 - serialNumValue2;
            });
            newProblemChapterList.addAll(problemChapterList);
        }
        return newProblemChapterList;
    }

    private void handleDirRelationPlan(Long dirId, PlanDesignInstance plan) {
        DirRelationPlan dirRelationPlan = new DirRelationPlan();
        dirRelationPlan.setDirId(dirId);
        dirRelationPlan.setPlanId(plan.getId());
        dirRelationPlan.setOwnerCode(plan.getCreatorCode());
        dirRelationPlanService.saveOrUpdate(dirRelationPlan);
    }

    /**
     * 方案重命名
     *
     * @param request 必填参数是：id、name
     */
    @Override
    public void rename(Map<String, Object> request) {
        long id = Long.parseLong(Objects.toString(request.get("id"), "-1"));
        String name = Objects.toString(request.get("name"), null);
        if (id == -1) {
            throw new BusinessException(Constants.PLAN_RENAME_FAILED_ID_REQUIRED);
        } else if (name == null) {
            throw new BusinessException(Constants.PLAN_RENAME_FAILED_NEW_NAME_REQUIRED);
        }

        PlanDesignInstance instance = planDesignInstanceDao.getById(id);
        if (instance == null) {
            throw new BusinessException(Constants.PLAN_NOT_FOUND);
        }

        checkNameWhileAdd(null, name, instance.getDirType());

        SysUser sysUser = SysUtil.getCurrentUserInfo();

        instance.setName(name);
        String secret = name;
        if (!StringUtils.isEmpty(instance.getDefaultSystemCiCode())) {
            secret = secret + instance.getDefaultSystemCiCode();
        }
        String businessKey = SecureUtil.md5(secret);
        instance.setBusinessKey(businessKey);
        instance.setModifyTime(ESUtil.getNumberDateTime());
        instance.setModifierCode(sysUser.getLoginCode());
        instance.setModifierName(sysUser.getUserName());

        planDesignInstanceDao.saveOrUpdate(instance);
    }

    /**
     * 批量删除到回收站 可恢复
     *
     * @param planIdList 方案集合
     * @param dirIdList  已经删除的文件夹Id
     */
    @Override
    public void deleteToRecycleBinBatch(List<Long> planIdList, List<Long> dirIdList) {
        List<PlanDesignInstance> planList = getPlanListByDirIdListAndPlanIdList(planIdList, dirIdList, PlanStatusEnum.draft);
        if (BinaryUtils.isEmpty(planList)) {
            return;
        }
        planList.removeIf(PlanDesignInstance::isProcessApproval);
        if (BinaryUtils.isEmpty(planList)) {
            resolveNotDeletedPlan(dirIdList);
            return;
        }
        Map<Long, Boolean> dirExistMap = itArchitectureDesignDirQueryService.getDirExistMap(planList, false);
        List<Long> deleteDafPlanIdList = Lists.newArrayList();
        List<String> deletePublishPlanIdList = Lists.newArrayList();
        for (PlanDesignInstance plan : planList) {
            plan.setRecyclable(true);
            // 记录当前状态 恢复时使用
            planSetTempWhenDeleting(plan, dirExistMap);
            if ("draft".equals(plan.getStatus())) {
                deleteDafPlanIdList.add(plan.getId());
            }
            if ("published".equals(plan.getStatus())) {
                deletePublishPlanIdList.add(plan.getBusinessKey());
            }
            plan.setDeleteBeforeStatus(plan.getStatus());
            plan.setStatus(PlanStatusEnum.deleted.name());
            plan.setTaskId("");
            // 方案如果再流程中，就结束流程
            TaskResponse taskInfo = flowableFeign.getCurrentOwnerTask(String.valueOf(plan.getId()), plan.getCreatorCode());
            if (taskInfo != null && !StringUtils.isEmpty(taskInfo.getProcessInstanceId())) {
                flowableFeign.terminateProcessInstanceById(taskInfo.getProcessInstanceId(), "驳回的方案被删除");
            }
        }
        planDesignInstanceDao.saveOrUpdateBatch(planList);
        if (!planList.isEmpty()) {
            //通过feign接口删除工作台的代办已办里面删除的方案
            WorkbenchChargeDoneVO workbenchChargeDoneVO = new WorkbenchChargeDoneVO();
            workbenchChargeDoneVO.setDeleteDafPlanIdList(deleteDafPlanIdList);
            workbenchChargeDoneVO.setDeletePublishPlanIdList(deletePublishPlanIdList);
            workbenchChargeDoneSvc.deleteWorkbenchChargeDone(workbenchChargeDoneVO);
        }
        // 解除方案关联的系统关系
        List<Long> ids = planList.stream().map(PlanDesignInstance::getId).collect(Collectors.toList());
        planSystemUnbind(ids);

        resolveNotDeletedPlan(dirIdList);
    }

    private void resolveNotDeletedPlan(List<Long> dirIdList) {

        if (BinaryUtils.isEmpty(dirIdList)) {
            return;
        }

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        queryBuilder.must(QueryBuilders.termsQuery("dirId", dirIdList));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));

        BoolQueryBuilder must = QueryBuilders.boolQuery();
        must.should(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.toString()));
        must.should(QueryBuilders.termQuery("processApproval", true));

        queryBuilder.must(must);

        List<PlanDesignInstance> planList = planDesignInstanceDao.getListByQuery(queryBuilder);

        if (BinaryUtils.isEmpty(planList)) {
            return;
        }
        // 过滤掉文件夹还存在的方案或者文件夹就是根目录的方案
        planList.removeIf(plan -> {
            Long dirId = plan.getDirId();
            return dirId != null && dirId == PlanDiagramDirBatchService.ROOT_DIR_ID;
        });

        if (BinaryUtils.isEmpty(planList)) {
            return;
        }

        // 剩下的就是文件夹不存在的方案 将他们移动到根目录
        for (PlanDesignInstance plan : planList) {
            plan.setDirId(PlanDiagramDirBatchService.ROOT_DIR_ID);
        }

        planDesignInstanceDao.saveOrUpdateBatch(planList);
    }

    /**
     * 回收站批量删除 不可恢复
     *
     * @param planIdList 方案集合
     * @param dirIdList  已经删除的文件夹Id
     */
    @Override
    public void removeFromRecycleBinBatch(List<Long> planIdList, List<Long> dirIdList) {
        List<PlanDesignInstance> planList = getPlanListByDirIdListAndPlanIdList(planIdList, dirIdList,
                PlanStatusEnum.deleted);
        if (BinaryUtils.isEmpty(planList)) {
            return;
        }
        long modifyTime = ESUtil.getNumberDateTime();
        for (PlanDesignInstance plan : planList) {
            plan.setRecyclable(false);
            plan.setStatus(PlanStatusEnum.deleted.name());
            plan.setModifyTime(modifyTime);
        }
        planDesignInstanceDao.saveOrUpdateBatch(planList);
    }

    List<PlanDesignInstance> getPlanListByDirIdListAndPlanIdList(List<Long> planIdList, List<Long> dirIdList,
                                                                 PlanStatusEnum statusEnum) {

        if (BinaryUtils.isEmpty(planIdList) && BinaryUtils.isEmpty(dirIdList)) {
            return Collections.emptyList();
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        if (!BinaryUtils.isEmpty(planIdList)) {
            queryBuilder.should(QueryBuilders.termsQuery("id", planIdList));
        }
        if (!BinaryUtils.isEmpty(dirIdList)) {
            BoolQueryBuilder must = QueryBuilders.boolQuery();
            must.must(QueryBuilders.termsQuery("dirId", dirIdList));
            must.must(QueryBuilders.termsQuery("status.keyword", statusEnum));
            must.must(QueryBuilders.termQuery("recyclable", true));
            queryBuilder.should(must);
        }

        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    /**
     * 回收站批量恢复
     *
     * @param planIdList 方案集合
     * @param dirIdSet   文件夹Id
     */
    @Override
    public void recoverBatch(List<Long> planIdList, Set<Long> dirIdSet) {
        List<PlanDesignInstance> planList = queryPlan(planIdList, dirIdSet);
        if (BinaryUtils.isEmpty(planList)) {
            return;
        }
        Map<String, PlanDesignInstance> duplicateNamePlanMap = filterDuplicateNamePlan(planList);
        Map<Long, Boolean> dirExistMap = itArchitectureDesignDirQueryService.getDirExistMap(planList, true);
        long modifyTime = ESUtil.getNumberDateTime();
        for (PlanDesignInstance plan : planList) {
            plan.setRecyclable(true);
            plan.setStatus(plan.getDeleteBeforeStatus());
            plan.setModifyTime(modifyTime);
            planSetDirWhenRecover(plan, dirExistMap);
            plan.setTemp(null);
        }
        planDesignInstanceDao.saveOrUpdateBatch(planList);
        // 恢复绑定的系统关系
        insertPlanSystemRelationBatch(planList);

        if (duplicateNamePlanMap.size() > 0) {
            throwPlanDuplicateNameException(duplicateNamePlanMap);
        }
    }

    private List<PlanDesignInstance> queryPlan(List<Long> planIdList, Set<Long> dirIdSet) {
        if (BinaryUtils.isEmpty(planIdList) && BinaryUtils.isEmpty(dirIdSet)) {
            return Collections.emptyList();
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        if (!BinaryUtils.isEmpty(planIdList)) {
            queryBuilder.should(QueryBuilders.termsQuery("id", planIdList));
        }
        if (!BinaryUtils.isEmpty(dirIdSet)) {
            BoolQueryBuilder must = QueryBuilders.boolQuery();
            must.must(QueryBuilders.termsQuery("dirId", dirIdSet));
            must.must(QueryBuilders.termsQuery("status.keyword", PlanStatusEnum.deleted.name()));
            must.must(QueryBuilders.termQuery("recyclable", true));
            queryBuilder.should(must);
        }
        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }

    private void throwPlanDuplicateNameException(Map<String, PlanDesignInstance> duplicateNamePlanMap) {
        Collection<PlanDesignInstance> duplicateNamePlanCollection = duplicateNamePlanMap.values();

        Map<Long, Boolean> dirExistMap =
                itArchitectureDesignDirQueryService.getDirExistMap(duplicateNamePlanCollection, false);

        List<String> nameList =
                duplicateNamePlanCollection.stream().map(PlanDesignInstance::getName).collect(Collectors.toList());

        String join = String.join(", ", nameList);
        String errorMsg = String.format(Constants.DUPLICATE_NAME_PLAN_RESTORE_FAILED_FORMAT, join);

        // 解释1: 回收站中的方案文件夹如果被恢复了 那么重名的方案移动到回收站的根目录
        // 解释2: 移除dir被删除的,剩下的就是目录被恢复的重名方案, 文件夹被恢复了, 那么这些方案就要移动到回收站的根目录
        duplicateNamePlanCollection.removeIf(p -> p.getDirId() == PlanDiagramDirBatchService.ROOT_DIR_ID ||
                !dirExistMap.get(p.getDirId()));
        if (!BinaryUtils.isEmpty(duplicateNamePlanCollection)) {
            duplicateNamePlanCollection.forEach(p -> p.setDirId(PlanDiagramDirBatchService.ROOT_DIR_ID));
            planDesignInstanceDao.saveOrUpdateBatch(ListUtil.toList(duplicateNamePlanCollection));
        }

        throw new BusinessException(errorMsg);
    }

    private Map<String, PlanDesignInstance> filterDuplicateNamePlan(List<PlanDesignInstance> planList) {
        Map<Long, String> map = planList.stream().collect(Collectors.toMap(PlanDesignInstance::getId, PlanDesignInstance::getName));
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("name.keyword", map.values()));
        query.must(QueryBuilders.termQuery("dirId", planList.get(0).getDirId()));
        query.must(QueryBuilders.termQuery("creatorCode.keyword", planList.get(0).getCreatorCode()));
        query.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
        query.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
        query.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.history.name()));
        query.mustNot(QueryBuilders.termsQuery("id", map.keySet()));
        List<PlanDesignInstance> list = planDesignInstanceDao.getListByQuery(query);
        if (BinaryUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }
        Map<String, PlanDesignInstance> duplicateNamePlanMap = list.stream().collect(Collectors.toMap(PlanDesignInstance::getName, p -> p));
        planList.removeIf(p -> duplicateNamePlanMap.get(p.getName()) != null);
        return duplicateNamePlanMap;
    }

    /**
     * 如果源文件夹存在(就是没有被删除),还原到源文件夹,否则还原到根文件夹
     */
    private void planSetDirWhenRecover(PlanDesignInstance plan, Map<Long, Boolean> dirExistMap) {
        PlanDesignInstance temp = plan.getTemp();
        if (temp == null) {
            plan.setDirId(PlanDiagramDirBatchService.ROOT_DIR_ID);
            return;
        }

        Long tempDirId = temp.getDirId();
        if (tempDirId == null) {
            plan.setDirId(PlanDiagramDirBatchService.ROOT_DIR_ID);
            return;
        }

        Boolean dirExist = dirExistMap.get(tempDirId);
        if (dirExist != null && dirExist) {
            plan.setDirId(tempDirId);
        } else {
            plan.setDirId(PlanDiagramDirBatchService.ROOT_DIR_ID);
        }
    }

    private void planSetTempWhenDeleting(PlanDesignInstance plan, Map<Long, Boolean> dirExistMap) {
        plan.setTemp(null);
        PlanDesignInstance temp = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, temp);
        plan.setTemp(temp);

        Long dirId = plan.getDirId();
        if (dirId != PlanDiagramDirBatchService.ROOT_DIR_ID) {

            Boolean dirExist = dirExistMap.get(dirId);
            // 文件夹还没有被删除时把方案删除到根目录
            boolean dirNotDeleted = dirExist != null && dirExist;
            if (dirNotDeleted) {
                plan.setDirId(PlanDiagramDirBatchService.ROOT_DIR_ID);
                // 记录原先的dirId 还原时使用
                plan.getTemp().setDirId(dirId);
            }
        }
    }

    /**
     * 方案批量移动
     *
     * @param targetDirId 目标文件夹
     * @param planIdList  要移动的方案
     */
    @Override
    public void moveBatch(Long targetDirId, List<Long> planIdList) {
        BoolQueryBuilder query = QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("id", planIdList));
        List<PlanDesignInstance> planList = planDesignInstanceDao.getListByQuery(query);
        BoolQueryBuilder dirNameQuery = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("dirId", targetDirId));
        List<PlanDesignInstance> dirPlans = planDesignInstanceDao.getListByQuery(dirNameQuery);
        if (dirPlans != null && dirPlans.size() > 0) {
            Set<String> planNameSet = dirPlans.stream().map(PlanDesignInstance::getName).collect(Collectors.toSet());
            for (PlanDesignInstance planDesignInstance : planList) {
                if (planNameSet.contains(planDesignInstance.getName())) {
                    throw new BusinessException("移动的方案与当前文件夹下方案名称重复:"+planDesignInstance.getName());
                }
            }
        }
        for (PlanDesignInstance plan : planList) {
            plan.setDirId(targetDirId);
        }

        planDesignInstanceDao.saveOrUpdateBatch(planList);
    }

    /**
     * 批量复制
     *
     * @param planIdList             方案id
     * @param oldDirIdAndNewDirIdMap 旧的id和新的id的映射关系
     * @param targetDirId            目标文件夹
     */
    @Override
    public void copyBatch(List<Long> planIdList, Map<Long, Long> oldDirIdAndNewDirIdMap, Long targetDirId) {
        List<PlanDesignInstance> sourcePlanList = new LinkedList<>();
        // 合并选中的方案
        mergeSelectedPlan(planIdList, sourcePlanList);
        // 合并文件夹中的方案
        mergePlanInDir(oldDirIdAndNewDirIdMap, sourcePlanList);

        if (sourcePlanList.size() == 0) {
            return;
        }

        List<Long> mergedPlanIdList =
                sourcePlanList.stream().map(PlanDesignInstance::getId).collect(Collectors.toList());

        BoolQueryBuilder queryChapter = QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("planId", mergedPlanIdList));

        BoolQueryBuilder queryContext = QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("planId", mergedPlanIdList));

        List<ChapterInstance> sourceChapterList = planChapterInstanceDao.getListByQuery(queryChapter);
        List<ChapterContext> sourceContextList = chapterContextDao.getListByQuery(queryContext);

        // key源方案名称 value是新方案的名称
        Map<String, String> newPlanNameMap = getNewPlanNameMap(sourcePlanList);

        doCopyBatch(sourcePlanList, sourceChapterList, sourceContextList, targetDirId, newPlanNameMap,
                oldDirIdAndNewDirIdMap);
    }

    private Map<String, String> getNewPlanNameMap(List<PlanDesignInstance> sourcePlanList) {
        Map<String, String> newPlanNameMap = MapUtil.newHashMap(sourcePlanList.size());
        createNewPlanName(sourcePlanList, newPlanNameMap, 1);
        return newPlanNameMap;
    }

    @Override
    public List<PlanDesignInstance> findPlanList(Set<Long> dirIdList, LibType libType) {
        if (CollectionUtils.isEmpty(dirIdList)) {
            return Collections.emptyList();
        }
        if (!Objects.equals(libType, LibType.PRIVATE) && !Objects.equals(libType, LibType.DESIGN)) {
            return Collections.emptyList();
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if (Objects.equals(libType, LibType.PRIVATE)) {
            queryBuilder.must(QueryBuilders.termsQuery("dirId", dirIdList));
            queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted));
            queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
            queryBuilder.must(QueryBuilders.termsQuery("creatorCode.keyword", SysUtil.getCurrentUserInfo().getLoginCode()));
        } else if (Objects.equals(libType, LibType.DESIGN)) {
            queryBuilder.must(QueryBuilders.termsQuery("assetsDirId", dirIdList));
            queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published));
            queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        }
        return planDesignInstanceDao.getListByQuery(queryBuilder);
    }


    private void doCopyBatch(List<PlanDesignInstance> sourcePlanList, List<ChapterInstance> sourceChapterList,
                             List<ChapterContext> sourceContextList, Long targetDirId,
                             Map<String, String> newPlanNameMap, Map<Long, Long> oldDirIdAndNewDirIdMap) {
        long time = ESUtil.getNumberDateTime();
        for (PlanDesignInstance plan : sourcePlanList) {
            Long sourcePlanId = plan.getId();
            Long newPlanId = ESUtil.getUUID();
            String newPlanName = findNewPlanName(newPlanNameMap, plan);
            Long sourcePlanDirId = plan.getDirId();
            Long newPlanDirId;
            if (BinaryUtils.isEmpty(oldDirIdAndNewDirIdMap)) {
                newPlanDirId = targetDirId;
            } else if ((newPlanDirId = oldDirIdAndNewDirIdMap.get(sourcePlanDirId)) == null) {
                newPlanDirId = targetDirId;
            }

            plan.setId(newPlanId);
            plan.setName(newPlanName);
            plan.setCreateTime(time);
            plan.setStatus(PlanStatusEnum.draft.name());
            plan.setModifyTime(time);
            plan.setDirId(newPlanDirId);
            plan.setProcessApproval(false);
            plan.setAssetsType(Constants.DESIGN);
            String secret = plan.getName();
            if (!StringUtils.isEmpty(plan.getDefaultSystemCiCode())) {
                secret = secret + plan.getDefaultSystemCiCode();
            }
            String businessKey = SecureUtil.md5(secret);
            plan.setBusinessKey(businessKey);
            plan.setTaskId("");

            copyChapterBatch(sourceChapterList, sourceContextList, time, sourcePlanId, newPlanId);

        }

        // 方案持久化
        savePlanBatch(sourcePlanList, sourceChapterList, sourceContextList);
        //处理方案发布位置
        for (PlanDesignInstance plan : sourcePlanList) {
            plan.setAssetsDirId(null);
            planInstanceServiceExtend.getPlanReleaseDirInfo(plan);
        }
        // 关联系统
        insertPlanSystemRelationBatch(sourcePlanList);

    }

    private void savePlanBatch(List<PlanDesignInstance> planList, List<ChapterInstance> chapterList,
                               List<ChapterContext> chapterContextList) {

        planDesignInstanceDao.saveOrUpdateBatch(planList);
        planChapterInstanceDao.saveOrUpdateBatch(chapterList);
        chapterContextDao.saveOrUpdateBatch(chapterContextList);
    }

    private void copyChapterBatch(List<ChapterInstance> sourceChapterList, List<ChapterContext> sourceContextList,
                                  long time, Long sourcePlanId, Long newPlanId) {

        Map<Long, Long> sourceIDAndNewId = MapUtil.newHashMap(sourceChapterList.size());
        List<ChapterInstance> incompleteChapterList = new LinkedList<>();
        long rootChapterId = 0;
        for (ChapterInstance chapter : sourceChapterList) {
            if (!chapter.getPlanId().equals(sourcePlanId)) {
                continue;
            }

            Long sourceChapterId = chapter.getId();
            Long newChapterId = ESUtil.getUUID();

            chapter.setId(newChapterId);
            chapter.setPlanId(newPlanId);
            chapter.setCreateTime(time);
            chapter.setModifyTime(time);
            chapter.setBusinessId(String.valueOf(ESUtil.getUUID()));
            chapter.setVersion(String.valueOf(ESUtil.getUUID()));
            chapter.setStatus(Constants.DRAFT);

            if (chapter.getParentId() != rootChapterId) {
                Long parentId = chapter.getParentId();
                parentId =  sourceIDAndNewId.get(parentId);
                if (parentId == null) {
                    incompleteChapterList.add(chapter);
                } else {
                    chapter.setParentId(parentId);
                }
            }

            sourceIDAndNewId.put(sourceChapterId, newChapterId);

            copyChapterContextBatch(sourceContextList, newPlanId, sourceChapterId, newChapterId);

            planArtifactService.copyPlanArtifact(sourcePlanId, sourceChapterId, newPlanId, newChapterId);
        }

        if (!BinaryUtils.isEmpty(incompleteChapterList)) {
            for (ChapterInstance chapter : incompleteChapterList) {
                Long parentId = chapter.getParentId();
                parentId =  sourceIDAndNewId.get(parentId);
                chapter.setParentId(parentId);
            }
        }
    }

    private void copyChapterContextBatch(List<ChapterContext> sourceContextList, Long newPlanId, Long sourceChapterId,
                                         Long newChapterId) {
        for (ChapterContext context : sourceContextList) {
            if (!context.getId().equals(sourceChapterId)) {
                continue;
            }

            context.setId(newChapterId);
            context.setPlanId(newPlanId);
            context.setBusinessId(String.valueOf(ESUtil.getUUID()));
            context.setVersion(String.valueOf(ESUtil.getUUID()));
            context.setStatus(Constants.DRAFT);
        }
    }

    private String findNewPlanName(Map<String, String> newPlanNameMap, PlanDesignInstance plan) {
        String newPlanName = plan.getName();
        while (newPlanNameMap.get(newPlanName) != null) {
            newPlanName = newPlanNameMap.get(newPlanName);
        }
        return newPlanName;
    }

    private void createNewPlanName(List<PlanDesignInstance> duplicateNamePlanList, Map<String, String> nameDict,
                                   int num) {

        Map<String, String> candidateNameDict =
                duplicateNamePlanList.stream().collect(Collectors.toMap(PlanDesignInstance::getName,
                        s -> String.format("%s(%s)", s.getName(), num)));

        BoolQueryBuilder query = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.draft.name()))
                .must(QueryBuilders.termsQuery("name.keyword", candidateNameDict.values()));

        duplicateNamePlanList = planDesignInstanceDao.getListByQuery(query);

        nameDict.putAll(candidateNameDict);
        if (!BinaryUtils.isEmpty(duplicateNamePlanList)) {
            Map<String, String> reverseCandidateNameDict = MapUtil.reverse(candidateNameDict);
            duplicateNamePlanList.forEach(p -> {
                String name = p.getName();
                p.setName(reverseCandidateNameDict.get(name));
            });
            createNewPlanName(duplicateNamePlanList, nameDict, (num + 1));
        }
    }

    private void mergePlanInDir(Map<Long, Long> oldDirIdAndNewDirIdMap, List<PlanDesignInstance> sourcePlanList) {
        if (BinaryUtils.isEmpty(oldDirIdAndNewDirIdMap)) {
            return;
        }

        Set<Long> oldDirIdList = oldDirIdAndNewDirIdMap.keySet();
        List<PlanDesignInstance> planList = planDesignInstanceDao.getListByQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("dirId", oldDirIdList))
                .mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name())));

        if (!BinaryUtils.isEmpty(planList)) {
            sourcePlanList.addAll(planList);
        }
    }

    private void mergeSelectedPlan(List<Long> planIdList, List<PlanDesignInstance> sourcePlanList) {
        if (BinaryUtils.isEmpty(planIdList)) {
            return;
        }

        List<PlanDesignInstance> planList = planDesignInstanceDao.getListByQuery(QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("id", planIdList)));

        if (!BinaryUtils.isEmpty(planList)) {
            sourcePlanList.addAll(planList);
        }
    }

    /**
     * 根据classId查询系统列表
     *
     * @param classId class分类id
     * @param libType 库
     * @return list
     */
    @Override
    public List<Map<String, String>> getSystemList(Long classId, LibType libType) {
        ESCISearchBean bean = new ESCISearchBean();
        bean.setClassIds(ListUtil.list(false, classId));
        CiGroupPage ciGroupPage = ciInfoService.getCiList(libType, bean);

        if (ciGroupPage.getTotalRows() == 0) {
            return ListUtil.empty();
        }

        return ciGroupPage.getData().stream().map(page -> {
            CcCi ci = page.getCi();
            Map<String, String> sysMap = MapUtil.newHashMap(2);
            sysMap.put("ciCode", ci.getCiCode());
            sysMap.put("name", getSysName(ci));
            return sysMap;
        }).collect(Collectors.toList());
    }

    private String getSysName(CcCi ci) {
        String ciLabel = ci.getCiLabel();
        List<String> datas = JSONObject.parseArray(ciLabel, String.class);
        if (!BinaryUtils.isEmpty(ciLabel) && !CollectionUtils.isEmpty(datas)) {
            String[] strings1 = datas.toArray(new String[0]);
            return StringUtils.join(strings1, ",");
        }

        return formatSysName(ci.getCiPrimaryKey());
    }

    private String formatSysName(String ciPrimaryKey) {
        List<String> strings = JSONObject.parseArray(ciPrimaryKey, String.class);
        if (!CollectionUtils.isEmpty(strings)) {
            strings.remove(0);
            String[] strings1 = strings.toArray(new String[0]);
            return StringUtils.join(strings1, ",");
        }
        return null;
    }

    /**
     * 查找回收站
     *
     * @param pageNum  页码
     * @param pageSize 个数
     * @param word     搜索词
     * @return {@link PlanDesignInstanceVO}
     */
    @Override
    public Page<PlanDesignInstanceVO> queryRecycleBin(int pageNum, int pageSize, Long dirId, String word) {

        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()))
                .must(QueryBuilders.termQuery("dirId", dirId))
                .must(QueryBuilders.termQuery("creatorCode.keyword", loginCode))
                .must(QueryBuilders.termQuery("recyclable", true));

        if (StringUtils.isNotBlank(word)) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(word, "name")
                    .operator(Operator.AND).type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
        }

        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("modifyTime").order(SortOrder.DESC);

        Page<PlanDesignInstance> page = planDesignInstanceDao.getSortListByQuery(pageNum, pageSize,
                boolQueryBuilder, ListUtil.list(false,
                        sortBuilder));

        Page<PlanDesignInstanceVO> planDesignInstanceVOPage = new Page<>(page.getPageNum(), page.getPageSize(),
                page.getTotalRows(), page.getTotalPages(), null);
        if (page.getTotalRows() <= 0) {
            planDesignInstanceVOPage.setData(Collections.emptyList());
        } else {
            List<PlanDesignInstanceVO> list = new ArrayList<>();
            for (PlanDesignInstance instance : page.getData()) {
                PlanDesignInstanceVO vo = new PlanDesignInstanceVO();
                // PO转VO
                BeanUtils.copyProperties(instance, vo);
                PlanDesignInstance temp = instance.getTemp();
                if (temp != null) {
                    vo.setOldDirId(temp.getDirId());
                }
                list.add(vo);
            }
            planDesignInstanceVOPage.setData(list);
        }

        return planDesignInstanceVOPage;
    }

    private String getCopyPlanName(PlanDesignInstance copyPlanDesignInstance) {
        StringBuilder stringBuilder = new StringBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("name,keyword", copyPlanDesignInstance.getName()));
        List<PlanDesignInstance> planDesignInstance = planDesignInstanceDao.getListByQuery(boolQueryBuilder);
        for (PlanDesignInstance p : planDesignInstance) {
            stringBuilder.append("-copy");
        }
        return copyPlanDesignInstance.getName() + stringBuilder.toString();
    }

    /**
     * 先把层级是1的章节过滤出来进行复制
     * @param chapterInstances
     * @param copyPlanId
     * @param copyMap
     */
    private void copyChapter(List<ChapterInstance> chapterInstances, Long copyPlanId, Map<Long, Long> copyMap) {
        //过滤出顶层
        List<ChapterInstance> parentChapterInstance = chapterInstances.stream().filter(item -> item.getLevel() == 1).collect(Collectors.toList());
        for (ChapterInstance chapterInstance : parentChapterInstance) {
            long copyChapterId = ESUtil.getUUID();
            Long chapterId = chapterInstance.getId();
            copyMap.put(chapterId,copyChapterId);
            chapterInstance.setId(copyChapterId);
            chapterInstance.setPlanId(copyPlanId);
            chapterInstance.setCreateTime(BinaryUtils.getNumberDateTime());
            chapterInstance.setModifyTime(BinaryUtils.getNumberDateTime());
            planChapterInstanceDao.saveOrUpdate(chapterInstance);
            //复制章节下面定义的内容
            ChapterContext chapterContext = chapterContextDao.getById(chapterId);
            chapterContext.setPlanId(copyPlanId);
            chapterContext.setId(copyChapterId);
            chapterContextDao.saveOrUpdate(chapterContext);
        }
        //下面递归实现复制子章节复制
        copyChildChapter(chapterInstances,copyPlanId,copyMap);
    }

    private void copyChildChapter(List<ChapterInstance> chapterInstances, Long copyPlanId, Map<Long, Long> copyMap) {
        Set<Long> chapterFatherIds = copyMap.keySet();
        List<ChapterInstance> childChapterInstanceList = chapterInstances.stream().filter(item -> chapterFatherIds.contains(item.getParentId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(copyMap)) {
            return;
        }
        Map<Long,Long> childMap = new HashMap<>();
        for (ChapterInstance chapterInstance : childChapterInstanceList) {
            long copyChapterId = ESUtil.getUUID();
            Long chapterId = chapterInstance.getId();
            childMap.put(chapterId,copyChapterId);
            chapterInstance.setId(copyChapterId);
            chapterInstance.setParentId(copyMap.get(chapterInstance.getParentId()));
            chapterInstance.setPlanId(copyPlanId);
            chapterInstance.setCreateTime(BinaryUtils.getNumberDateTime());
            chapterInstance.setModifyTime(BinaryUtils.getNumberDateTime());
            planChapterInstanceDao.saveOrUpdate(chapterInstance);
            //复制章节下面定义的内容
            ChapterContext chapterContext = chapterContextDao.getById(chapterId);
            chapterContext.setPlanId(copyPlanId);
            chapterContext.setId(copyChapterId);
            chapterContextDao.saveOrUpdate(chapterContext);
        }
        copyChildChapter(chapterInstances,copyPlanId,childMap);
    }

    private List<ChapterInstance> findAllChapterInstance(Long planId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planId", planId));
        query.must(QueryBuilders.termQuery("deleted", false));
        return planChapterInstanceDao.getListByQuery(query);
    }


    /**
     * 方案设计更改
     *
     * @param request {@link PlanDesignInstanceUpdateRequest}
     */
    @Override
    public Long update(PlanDesignInstanceUpdateRequest request) {
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(request.getId());
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案错误!");
        }
        PlanDesignInstanceVO plan = this.getById(request.getId());
        if (planDesignInstance.isProcessApproval() && !plan.isEdit()) {
            return -1L;
        }

        // 判断是否有权限操作方案
        SysUser user = SysUtil.getCurrentUserInfo();
        if (!Objects.equals(user.getLoginCode(), planDesignInstance.getCreatorCode())) {
            List<PlanDesignShareRecord> shareRecordList = shareService.getByPlanId(planDesignInstance.getId());
            if (!CollectionUtils.isEmpty(shareRecordList)) {
                Map<String, Integer> shareRecordMap = shareRecordList.stream().collect(Collectors.toMap(PlanDesignShareRecord::getSharedLoginCode, PlanDesignShareRecord::getPermission));
                if (shareRecordMap == null || shareRecordMap.get(user.getLoginCode()) == null
                        || (!Objects.equals(shareRecordMap.get(user.getLoginCode()), 1)
                        && !Objects.equals(shareRecordMap.get(user.getLoginCode()), 2)
                        && !Objects.equals(shareRecordMap.get(user.getLoginCode()), 4))) {
                    throw new BusinessException("暂无权限操作方案!");
                }
            } else {
                throw new BusinessException("暂无权限操作方案!");
            }
        }

        // 校验是否重名
        checkNameWhileUpdate(request, planDesignInstance.getDirType());

        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        String loginCode = currentUserInfo.getLoginCode();
        long time = ESUtil.getNumberDateTime();

        BeanUtils.copyProperties(request, planDesignInstance);

        // 设置业务中间，名称 + ciCode
        String secret = planDesignInstance.getName();
        if (!StringUtils.isEmpty(planDesignInstance.getDefaultSystemCiCode())) {
            secret = secret + request.getDefaultSystemCiCode();
        }
        String businessKey = SecureUtil.md5(secret);
        planDesignInstance.setBusinessKey(businessKey);

        PlanDesignInstance instance = new PlanDesignInstance();
        instance.setModifierCode(loginCode);
        instance.setModifyTime(time);
        instance.setProcessApproval(planDesignInstance.isProcessApproval());
        CSysUser cdt = new CSysUser();
        cdt.setLoginCodeEqual(loginCode);
        List<SysUser> sysUserList = userApiSvc.getSysUserByCdt(cdt);
        if (!CollectionUtils.isEmpty(sysUserList)) {
            SysUser sysUser = sysUserList.get(0);
            instance.setModifierName(sysUser.getUserName());
        }

        try {
            for (Field field : PlanDesignInstance.class.getDeclaredFields()) {
                field.setAccessible(true);
                Object value = field.get(instance);
                if (value != null) {
                    field.set(planDesignInstance, value);
                }
            }
            planDesignInstanceDao.saveOrUpdate(planDesignInstance);
        } catch (Exception e) {
            log.error("SystemException：", e);
            throw new BusinessException(e.getMessage());
        }

        updatePlanSystemRelation(planDesignInstance);
        return 1L;
    }

    private void updatePlanSystemRelation(PlanDesignInstance instance) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.termQuery("planId", instance.getId()));

        String script = String.format("ctx._source.status=%s", Constants.DELETED_STATUS);
        planSystemRelationDao.updateByQuery(builder, script, true);

        insertPlanSystemRelation(instance);
    }

    /**
     * 方案设计分页查询
     */
    @Override
    public Page<PlanDesignInstance> list(PlanDesignInstanceQueryRequest request, SysUser sysUser) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        if (StringUtils.isBlank(request.getStatus())) {
            mustNotKeyword(builder, "status", PlanStatusEnum.deleted.name());
        } else {
            mustKeyword(builder, "status", request.getStatus());
        }

        if (request.getTemplateId() != null) {
            builder.must(QueryBuilders.termQuery("templateId", request.getTemplateId()));
        }

        if (request.getTypeId() != null) {
            builder.must(QueryBuilders.termQuery("typeId", request.getTypeId()));
        }

        if (StringUtils.isNotBlank(request.getWord())) {
            builder.must(QueryBuilders.multiMatchQuery(request.getWord(), "name")
                    .operator(Operator.AND).type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
        }

        if (request.getSystemId() != null) {
            builder.must(QueryBuilders.matchQuery("systemIdList",request.getSystemId()));
        }


        Date startTime = request.getStartTime();
        Date endTime = request.getEndTime();
        if (startTime != null && endTime != null) {
            long start = ESUtil.getNumberDateTime(startTime);
            long end = ESUtil.getNumberDateTime(endTime);
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createTime").from(start)
                    .to(end);
            builder.must(rangeQueryBuilder);
        } else if (startTime != null) {
            long start = ESUtil.getNumberDateTime(startTime);
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createTime").gte(start);
            builder.must(rangeQueryBuilder);
        } else if (endTime != null) {
            long end = ESUtil.getNumberDateTime(endTime);
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createTime").lte(end);
            builder.must(rangeQueryBuilder);
        }

        builder.must(QueryBuilders.termQuery("creatorCode.keyword", sysUser.getLoginCode()));

        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
        return planDesignInstanceDao.getSortListByQuery(request.getPageNum(), request.getPageSize(), builder, sorts);
    }

    /**
     * 根据id查询
     * <font color="yellow">重要:需要修改的方法, 查询名称需要重写</font>
     */
    @Override
    public PlanDesignInstanceVO getById(Long id) {
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        PlanDesignInstance plan = null;
        try {
            plan = planDesignInstanceDao.getById(id);
        } catch (Exception e) {
            throw new BusinessException("方案已被删除!");
        }
        if (plan == null) {
            throw new BusinessException("方案已被删除!");
        }
        PlanDesignInstanceVO vo = new PlanDesignInstanceVO();
        BeanUtils.copyProperties(plan, vo);
        vo.setSystemList(plan.getCiCodeList().stream().map(ciCode -> {
            Map<String, Object> map = new HashMap<>((int) (1 / 0.75) + 1);
            map.put("ciCode", ciCode);
            return map;
        }).collect(Collectors.toList()));

        DlvrTemplateVO template = null;
        if (plan.getTemplateId() != null) {
            template = deliverableTemplateService.getDlvrTemplateById(plan.getTemplateId());
            if (template != null) {
                if (!StringUtils.isEmpty(template.getTemplateName())) {
                    vo.setTemplateName(template.getTemplateName());
                }
                if (!StringUtils.isEmpty(template.getProposalName())) {
                    vo.setTypeName(template.getProposalName());
                }
            }
        }
        planInstanceServiceExtend.getPlanReleaseDirInfo(plan, template);
        vo.setAssetsDirId(plan.getAssetsDirId());
        vo.setEchoDirName(plan.getEchoDirName());

        //模板类型是否是"架构方案"
        String configJson = bmConfigSvc.getConfigType("AXEA_CONFIG");
        if (StringUtils.isBlank(configJson)) {
            throw new BinaryException("未查询到国投配置，请联系管理员");
        }
        JSONObject conf = JSON.parseObject(configJson);
        TemplateType templateType = getArchReviewTemplateType(conf);

        TaskResponse taskInfo = null;
        if (templateType.getId().equals(plan.getTypeId())) {
            String bizKey = queryArchReviewBizKey(plan.getId());
            if (StringUtils.isNotBlank(bizKey)) {
                taskInfo = flowableFeign.getCurrentTaskDefinitionInfo(bizKey, FlowableConstant.GT_TECHNICAL_SCHEME_APPROVE);
            }
        } else if (template != null && template.getApprovalType() != null && Objects.equals(template.getApprovalType(), 1)) {
            taskInfo = flowableFeign.getCurrentTaskDefinitionInfo(String.valueOf(id), FlowableConstant.PLAN_DEFINITION_KEY2);
        } else {
            taskInfo = flowableFeign.getCurrentTaskDefinitionInfo(String.valueOf(id), FlowableConstant.PLAN_DEFINITION_KEY1);
        }

        if (taskInfo != null) {
            if (!StringUtils.isEmpty(taskInfo.getProcessInstanceId())) {
                vo.setProcessInstanceId(taskInfo.getProcessInstanceId());
            }
            if (!StringUtils.isEmpty(taskInfo.getTaskDefinitionKey())) {
                //国投这里问题/批注都只跟流程有关系
                vo.setTaskDefinitionKey(taskInfo.getProcessInstanceId());
            }
        }

        TaskResponse taskResponse = null;
        if (templateType.getId().equals(plan.getTypeId())) {
            String bizKey = queryArchReviewBizKey(plan.getId());
            if (StringUtils.isNotBlank(bizKey)) {
                taskResponse = flowableFeign.getCurrentTaskAssignees(bizKey, FlowableConstant.GT_TECHNICAL_SCHEME_APPROVE);
            }
        } else if (template != null && template.getApprovalType() != null && Objects.equals(template.getApprovalType(), 1)) {
            taskResponse = flowableFeign.getCurrentTaskAssignees(String.valueOf(id), FlowableConstant.PLAN_DEFINITION_KEY2);
        } else {
            taskResponse = flowableFeign.getCurrentTaskAssignees(String.valueOf(id), FlowableConstant.PLAN_DEFINITION_KEY1);
        }
        if (taskResponse != null) {
            SysUser currentUserInfo = sysUser;
            if (!StringUtils.isEmpty(taskResponse.getSubmitter()) && !Objects.equals(currentUserInfo.getLoginCode(), taskResponse.getSubmitter()) &&
                    !StringUtils.isEmpty(taskResponse.getCurrentAssignees()) && taskResponse.getCurrentAssignees().contains(currentUserInfo.getLoginCode())) {
                boolean auth = false;
                for (String currentAssingess : taskResponse.getCurrentAssignees().split(",")) {
                    if (currentAssingess.equals(currentUserInfo.getLoginCode())) {
                        auth = true;
                        break;
                    }
                }
                vo.setHandleAnnotation(auth);
            } else {
                vo.setHandleAnnotation(false);
            }
        } else {
            vo.setHandleAnnotation(false);
        }

        // 获取方案分享状态
        if (!Objects.equals(plan.getCreatorCode(), sysUser.getLoginCode()) && Objects.equals(plan.getAssetsType(), Constants.DESIGN)) {
            BoolQueryBuilder builder = QueryBuilders.boolQuery();
            builder.must(QueryBuilders.termQuery("planDesignId", id));
            builder.must(QueryBuilders.termQuery("sharedLoginCode.keyword", sysUser.getLoginCode()));
            builder.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
            List<PlanDesignShareRecord> shareRecordList = planDesignShareRecordDao.getListByQuery(builder);
            if (!CollectionUtils.isEmpty(shareRecordList)) {
                PlanDesignShareRecord shareRecord = shareRecordList.get(0);
                if (shareRecord != null && shareRecord.getPermission() != null) {
                    vo.setPermission(shareRecord.getPermission());
                }
            } else {
                vo.setPermission(PlanSharePermissionEnum.READ_ONLY.getFlag());
            }
        }

        // 如果方案是资产库，获取发布位置
        if (Objects.equals(plan.getAssetsType(), 2)) {
            BoolQueryBuilder boolQueryDirBuilder = QueryBuilders.boolQuery();
            boolQueryDirBuilder.must(QueryBuilders.termQuery("id", plan.getAssetsDirId()));
            List<EamCategory> dirList = categoryDesignDao.getListByQuery(boolQueryDirBuilder);
            if (!CollectionUtils.isEmpty(dirList)) {
                EamCategory eamCategory = dirList.get(0);
                String path = eamCategory.getDirPath().substring(1, eamCategory.getDirPath().length() - 1);
                String[] pathIds = path.split("#");
                if (pathIds.length > 0) {
                    List<Long> collect = Arrays.stream(pathIds).filter(pathId -> pathId != null).map(pathId -> Long.valueOf(pathId)).collect(Collectors.toList());
                    List<EamCategory> eamCategoryList = categorySvc.getByIds(collect, LibType.DESIGN);
                    if (!CollectionUtils.isEmpty(eamCategoryList)) {
                        Map<Long, EamCategory> eamCategoryMap = eamCategoryList.stream().collect(Collectors.toMap(EamCategory::getId, item -> item));
                        StringBuffer sb = new StringBuffer(1000);
                        for (Long categoryId : collect) {
                            EamCategory category = eamCategoryMap.get(categoryId);
                            if (category != null && !StringUtils.isEmpty(category.getDirName())) {
                                sb.append(category.getDirName()).append("/");
                            }
                        }
                        String echoDirName = sb.substring(0, sb.length() - 1);
                        vo.setEchoDirName(echoDirName);
                    }
                }
            }
        }
        // 判断是否是发布状态
        /*if (!vo.isProcessApproval() && !StringUtils.isEmpty(plan.getBusinessKey())) {
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            query.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
            query.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
            List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(query);
            if (!CollectionUtils.isEmpty(planDesignInstanceList)) {
                vo.setStatus(PlanStatusEnum.published.name());
            }
        }*/
        //审批中（可编辑）状态放开编辑权限
        if (PlanStatusEnum.approve_edit.name().equals(vo.getStatus())) {
            vo.setEdit(true);
        }
        vo.setAssertDirEdit(getAssertDirEdit(vo, template));
        setProcessSubmitter(vo);
        setArchReview(vo);
        return vo;
    }

    private String queryArchReviewBizKey(Long planId) {
        TermQueryBuilder query = QueryBuilders.termQuery("planIds", planId);
        Page<ArchReview> page = archReviewDao.getSortListByQuery(1,1, query,"createTime", false);
        return CollectionUtils.isEmpty(page.getData()) ? "" : page.getData().get(0).getId().toString();
    }

    private void setProcessSubmitter(PlanDesignInstanceVO plan) {
        if (plan == null) {
            return;
        }
        TaskResponse taskResponse = flowableFeign.getCurrentTaskDefinitionInfo(plan.getId().toString(), FlowableConstant.PLAN_DEFINITION_KEY1);
        if (taskResponse == null || StringUtils.isBlank(taskResponse.getProcessInstanceId())) {
            plan.setSubmitter(plan.getCreatorName());
            return;
        }
        PorcessResponse porcessResponse = flowableFeign.getProcessInstanceByProcessInstanceId(taskResponse.getProcessInstanceId());
        if (porcessResponse == null || StringUtils.isBlank(porcessResponse.getProcessStartUserId())) {
            plan.setSubmitter(plan.getCreatorName());
            return;
        }
        CSysUser cdt = new CSysUser();
        cdt.setLoginCodeEqual(porcessResponse.getProcessStartUserId());
        List<SysUser> users = userApiSvc.getSysUserByCdt(cdt);
        String submitter = CollectionUtils.isEmpty(users) ? porcessResponse.getProcessStartUserId() : users.get(0).getUserName();
        plan.setSubmitter(submitter);
    }

    private TemplateType getArchReviewTemplateType(JSONObject conf) {
        if (conf == null) {
            throw new BinaryException("未查询到国投分类映射配置，请联系管理员");
        }
        String archReviewTemplateTypeName = conf.getString("archReviewTemplateTypeName");
        if (StringUtils.isBlank(archReviewTemplateTypeName)) {
            throw new BinaryException("未查询到国投架构方案模板类型配置，请联系管理员");
        }
        TemplateType templateType = deliverableTemplateService.getTemplateTypeByName(archReviewTemplateTypeName);
        if (templateType == null) {
            log.error("未查询到国投架构方案模板类型配置[archReviewTemplateTypeName:{}]，请联系管理员", archReviewTemplateTypeName);
            throw new BinaryException("未查询到国投架构方案模板类型配置，请联系管理员");
        }
        return templateType;
    }

    private void setArchReview(PlanDesignInstanceVO plan) {
        String configJson = bmConfigSvc.getConfigType("AXEA_CONFIG");
        if (StringUtils.isBlank(configJson)) {
            throw new BinaryException("未查询到国投配置，请联系管理员");
        }
        JSONObject conf = JSON.parseObject(configJson);
        TemplateType templateType = getArchReviewTemplateType(conf);
        String axeaClassMapping = conf.getString("classMapping");
        if (StringUtils.isBlank(axeaClassMapping)) {
            throw new BinaryException("未查询到国投项目分类映射配置，请联系管理员");
        }
        JSONObject axeaClassConf = JSONObject.parseObject(axeaClassMapping);
        String projectClassCode = axeaClassConf.getString("projectClassCode");
        if (StringUtils.isBlank(projectClassCode)) {
            throw new BinaryException("未查询到国投项目分类映射配置，请联系管理员");
        }
        String[] projectClassCodes = new String[]{projectClassCode};
        CCcCiClass projectCdt = new CCcCiClass();
        projectCdt.setClassCodes(projectClassCodes);
        List<CcCiClassInfo> projectCiClassInfos = ciClassSvc.queryClassByCdt(projectCdt);
        if (CollectionUtils.isEmpty(projectCiClassInfos)) {
            String msg = "未查询到国投项目分类[projectClassCode:".concat(projectClassCode).concat("]，请联系管理员");
            throw new BinaryException(msg);
        }
        //模板非"架构方案"类型或绑定分类非"项目"分类，不做处理
        if (!templateType.getId().equals(plan.getTypeId())
                || !projectCiClassInfos.get(0).getCiClass().getId().equals(plan.getDefaultSystemClassId())) {
            plan.setPlanBindProject(Boolean.FALSE);
            return;
        }
        String systemClassCode = axeaClassConf.getString("systemClassCode");
        if (StringUtils.isBlank(systemClassCode)) {
            throw new BinaryException("未查询到国投系统分类映射配置，请联系管理员");
        }
        String[] systemClassCodes = new String[]{systemClassCode};
        CCcCiClass systemCdt = new CCcCiClass();
        systemCdt.setClassCodes(systemClassCodes);
        List<CcCiClassInfo> systemCiClassInfos = ciClassSvc.queryClassByCdt(systemCdt);
        if (CollectionUtils.isEmpty(systemCiClassInfos)) {
            String msg = "未查询到国投系统分类[systemClassCode:".concat(systemClassCode).concat("]，请联系管理员");
            throw new BinaryException(msg);
        }
        plan.setPlanBindProject(Boolean.TRUE);
        String names = "-";
        List<Map<String, String>> effectSystems = new ArrayList<>();
        if (!CollectionUtils.isEmpty(plan.getSystemCiCodes())) {
            List<CcCiInfo> systems = querySystemsByCiCodes(plan.getSystemCiCodes(), systemCiClassInfos.get(0).getCiClass().getId());
            List<String> systemNames = new ArrayList<>();
            if (!CollectionUtils.isEmpty(systems)) {
                for (CcCiInfo ciInfo : systems) {
                    String label = getLabel(ciInfo.getCi());
                    systemNames.add(label);
                    Map<String, String> s = new HashMap<>();
                    s.put("ciCode", ciInfo.getCi().getCiCode());
                    s.put("name", label);
                    effectSystems.add(s);
                }
            }
            names = CollectionUtils.isEmpty(systemNames) ? "-" : String.join(",", systemNames);
        }
        plan.setSystemNames(names);
        plan.setEffectSystems(effectSystems);
    }

    public List<CcCiInfo> querySystemsByCiCodes(List<String> ciCodes, Long systemClassId) {
        if (CollectionUtils.isEmpty(ciCodes)) {
            return new ArrayList<>();
        }
        //无label字段时返回空
        List<String> labelDefs = getLabelDefs(systemClassId);
        if (CollectionUtils.isEmpty(labelDefs)) {
            throw new BinaryException("系统分类暂无label字段");
        }
        ESCISearchBean bean = new ESCISearchBean();
        bean.setCiCodes(ciCodes);
        bean.setClassIds(Arrays.asList(systemClassId));
        bean.setDomainId(1L);
        bean.setPageNum(1);
        bean.setPageSize(ciCodes.size());
        CiGroupPage page = ciSwitchSvc.queryPageBySearchBean(bean, false, LibType.DESIGN);
        return page.getData();
        //if (CollectionUtils.isEmpty(page.getData())) {
        //    return new ArrayList<>();
        //}
        //List<String> systemNames = new ArrayList<>();
        //for (CcCiInfo ciInfo : page.getData()) {
        //    String label = getLabel(ciInfo.getCi());
        //    systemNames.add(label);
        //}
        //return systemNames;
    }

    private String getLabel(CcCi ci) {
        String ciLabel = ci.getCiLabel();
        if (StringUtils.isBlank(ciLabel)) {
            return null;
        }
        List<String> datas = JSONObject.parseArray(ciLabel, String.class);
        if (CollectionUtils.isEmpty(datas)) {
            return null;
        }
        return String.join("-", datas);
    }

    private List<String> getLabelDefs(Long classId) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("id", classId));
        List<ESCIClassInfo> ciClassInfos = classSvc.getSourceCIClassDefByQuery(query);
        if (CollectionUtils.isEmpty(ciClassInfos)) {
            return new ArrayList<>();
        }
        List<String> defs = new ArrayList<>();
        for (ESCIClassInfo cls : ciClassInfos) {
            cls.getCcAttrDefs().forEach(def -> {
                if (def.getIsCiDisp() != null && def.getIsCiDisp() == 1) {
                    defs.add(def.getProStdName());
                }
            });
        }
        return defs;
    }

    private Boolean getAssertDirEdit(PlanDesignInstanceVO instance, DlvrTemplateVO deliverableTemplate) {
        if (PlanStatusEnum.published.name().equals(instance.getStatus())) {
            EamCategory category = categorySvc.getById(instance.getAssetsDirId(), LibType.DESIGN);
            return category == null;
        }
        //发布位置不存在，可编辑
        if (instance.getAssetsDirId() == null) {
            return true;
        }
        //有发布位置且发布位置存在
        EamCategory category = categorySvc.getById(instance.getAssetsDirId(), LibType.DESIGN);
        if (category != null) {
            //系统文件夹看绑定资产
            if (category.getType() == 3) {
                //方案无绑定资产，可编辑
                if (StringUtils.isBlank(instance.getDefaultSystemCiCode())) {
                    return true;
                }
                //查不到方案绑定资产，可编辑
                List<ESCIInfo> esciInfos = ciSwitchSvc.getCiByCodes(Arrays.asList(instance.getDefaultSystemCiCode()), null, LibType.DESIGN);
                if (CollectionUtils.isEmpty(esciInfos)) {
                    return true;
                }
                //方案有绑定资产，能否编辑取决于当前文件夹是不是当前绑定资产的
                return !esciInfos.get(0).getCiCode().equals(category.getCiCode());
            }
            //普通文件夹看模板发布位置
            if (deliverableTemplate == null) {
                return true;
            }
            //模板没有发布位置
            Long assetsDirId = deliverableTemplate.getAssetsDirId();
            if (StringUtils.isBlank(deliverableTemplate.getEchoDirName()) || assetsDirId == null) {
                return true;
            }
            EamCategory templateAssetsDir = categorySvc.getById(assetsDirId, LibType.DESIGN);
            //模板发布位置不存在
            if (templateAssetsDir == null) {
                return true;
            }
            //模板发布位置和方案选的发布位置一样，不能编辑，反之能编辑
            return !templateAssetsDir.getId().equals(instance.getAssetsDirId());
        }
        //发布位置不存在，可编辑
        return true;

//        //模板没有绑定资产或方案无绑定资产
//        if (CollectionUtils.isEmpty(deliverableTemplate.getBindAssetList())
//                || StringUtils.isBlank(instance.getDefaultSystemCiCode())) {
//            return templateDirCanNotUse(deliverableTemplate);
//        }
//        //查绑定资产
//        List<ESCIInfo> esciInfos = ciSwitchSvc.getCiByCodes(Arrays.asList(instance.getDefaultSystemCiCode()), null, LibType.DESIGN);
//        if (CollectionUtils.isEmpty(esciInfos)) {
//            return templateDirCanNotUse(deliverableTemplate);
//        }
//        ESCIInfo ciInfo = esciInfos.get(0);
//        List<BindAssetVo> bindAssetList = deliverableTemplate.getBindAssetList();
//        BindAssetVo bindAssetVo = bindAssetList.get(0);
//        //绑定资产对应的分类和模板绑定资产分类不一致
//        if (!bindAssetVo.getClassId().equals(ciInfo.getClassId())) {
//            throw new BinaryException("绑定资产所属分类与模板绑定分类不一致");
//        }
//        String configJson = bmConfigSvc.getConfigType("AXEA_CONFIG");
//        if (StringUtils.isBlank(configJson)) {
//            throw new BinaryException("未查询到国投配置，请联系管理员");
//        }
//        JSONObject conf = JSON.parseObject(configJson);
//        if (StringUtils.isBlank(conf.getString("classConf"))) {
//            log.info("国投配置暂未配置分类配置，planId:{}", instance.getId());
//            return templateDirCanNotUse(deliverableTemplate);
//        }
//        JSONObject classConf = JSON.parseObject(conf.getString("classConf"));
//        CCcCiClass cdt = new CCcCiClass();
//        cdt.setId(bindAssetVo.getClassId());
//        List<CcCiClassInfo> classInfos = ciClassSvc.queryClassByCdt(cdt);
//        if (CollectionUtils.isEmpty(classInfos)) {
//            log.error("未找到交付物模板绑定的分类:ciClassId:{}", bindAssetVo.getClassId());
//            throw new BinaryException("未找到交付物模板绑定的分类");
//        }
//        CcCiClassInfo ciClassInfo = classInfos.get(0);
//        String ciClassCode = ciClassInfo.getCiClass().getClassCode();
//        //交付物模板绑定分类不在系统文件夹创建范围内
//        if (StringUtils.isBlank(classConf.getString(ciClassCode))) {
//            log.info("交付物模板绑定分类[ciClassCode:{}]不在系统文件夹创建范围内，classConf:{}", ciClassCode, classConf.toJSONString());
//            return templateDirCanNotUse(deliverableTemplate);
//        }
//        //查资产仓库系统文件夹
//        EamCategory category = categorySvc.getByCiCode(instance.getDefaultSystemCiCode(), null, LibType.DESIGN);
//        //兼容发布位置为空但是资产实例文件存在的场景
//        if (category != null) {
//            return instance.getAssetsDirId() == null;
//        }
//        return true;
    }

    /**
     * 模板发布位置是否可用
     * @param deliverableTemplate
     * @return
     */
    private Boolean templateDirCanNotUse(DlvrTemplateVO deliverableTemplate) {
        //模板没有发布位置
        Long assetsDirId = deliverableTemplate.getAssetsDirId();
        if (StringUtils.isBlank(deliverableTemplate.getEchoDirName()) || assetsDirId == null) {
            return true;
        }
        EamCategory eamCategory = categorySvc.getById(assetsDirId, LibType.DESIGN);
        //模板的发布位置不存在
        if (eamCategory == null) {
            return true;
        }
        return false;
    }

    /**
     * 查询系统名称
     * <font color="yellow">重要:需要修改的方法</font>
     */
    private Object getSystemName(Long systemId, List<Map<String, Object>> systemList) {
        Optional<Map<String, Object>> result = systemList.stream().filter(systemInfo -> systemInfo.get("id").equals(systemId)).findFirst();
        return !result.isPresent() ? "" : result.get().get("name");
    }

    /**
     * 根据id删除
     *
     * @param id 方案设计的id
     */
    @Override
    public void deleteToRecycleBin(Long id) {
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(id);
        String status = planDesignInstance.getStatus();
        if (!PlanStatusEnum.draft.name().equals(status)) {
            throw new BusinessException("删除失败: 只有草稿方案才能删除");
        }

        if (planDesignInstance.isProcessApproval()) {
            throw new BusinessException("方案已在流程中，删除失败!");
        }

        planDesignInstance.setStatus(PlanStatusEnum.deleted.name());
        planDesignInstance.setRecyclable(true);
        planDesignInstance.setModifyTime(ESUtil.getNumberDateTime());
        planDesignInstanceDao.saveOrUpdate(planDesignInstance);

        planSystemUnbind(ListUtil.list(false, id));
    }

    /**
     * 批量解除方案关联的系统关系
     *
     * @param planIdList 方案list
     */
    private void planSystemUnbind(List<Long> planIdList) {
        if (BinaryUtils.isEmpty(planIdList)) {
            return;
        }
        // 修改关联系统状态
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("planId", planIdList));
        List<PlanSystemRelation> planSystemList = planSystemRelationDao.getListByQuery(query);
        if (BinaryUtils.isEmpty(planSystemList)) {
            return;
        }
        planSystemList.forEach(planSystem -> {
            planSystem.setPreviousStatus(planSystem.getStatus());
            planSystem.setStatus(Constants.DELETED_STATUS);
        });
        planSystemRelationDao.saveOrUpdateBatch(planSystemList);
    }

    @Override
    public Long addOrUpdateShareRecord(PlanDesignShareRecord planDesignShareRecord) {
        if (planDesignShareRecord == null) {
            throw new BusinessException("参数不能为空!");
        }
        if (planDesignShareRecord.getPlanDesignId() == null) {
            throw new BusinessException("方案主键不能为空!");
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(planDesignShareRecord.getPlanDesignId());
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();

        /**
         * 判断当前用户是否有 管理员菜单<架构设计清单> 菜单权限 (一般只有管理员有这个菜单权限)
         * 有此菜单权限的  都可以 查看/分享/协作 视图/方案
         * 菜单名称：架构设计清单  后续可能会更改 通过配置可配：admin.menu.name
         * @return
         */
        boolean needAuth = true; //是否需要权限判断
        boolean isAdminRole = userApiSvc.isAdminRole();
        if (isAdminRole) {
            needAuth = false;
        }
        // 判断是否有权限操作方案
        if (!Objects.equals(loginCode, plan.getCreatorCode()) && needAuth) {
            PlanDesignShareRecord record = new PlanDesignShareRecord();
            record.setPlanDesignId(plan.getId());
            record.setSharedLoginCode(loginCode);
            record.setStatus(PlanShareEnum.SHARING.getStatus());
            List<PlanDesignShareRecord> shareRecordList = shareService.findPlanShareRecordList(record);
            if (!CollectionUtils.isEmpty(shareRecordList)) {
                PlanDesignShareRecord shareRecord = shareRecordList.get(0);
                if (!Objects.equals(shareRecord.getPermission(), 1)
                        && !Objects.equals(shareRecord.getPermission(), 4)) {
                    throw new BusinessException("暂无权限操作方案!");
                }
            } else {
                if (!plan.isProcessApproval()) {
                    return -1L;
                } else {
                    throw new BusinessException("暂无权限操作方案!");
                }
            }
        }

        Integer permission = planDesignShareRecord.getPermission();
        // 验证方案是否属于当前用户
        checkPermission(planDesignShareRecord, loginCode, needAuth);
        String[] sharedLoginCodes = planDesignShareRecord.getSharedLoginCode().split(",");

        if (sharedLoginCodes.length > 0) {
            List<PlanDesignShareRecord> shareRecordList = new ArrayList<>();
            for (String sharedLoginCode : sharedLoginCodes) {
                PlanDesignShareRecord newPlanDesignShareRecord = new PlanDesignShareRecord();

                BoolQueryBuilder query = QueryBuilders.boolQuery();
                query.must(QueryBuilders.termQuery("planDesignId", planDesignShareRecord.getPlanDesignId()));
                query.must(QueryBuilders.termQuery("sharedLoginCode.keyword", sharedLoginCode));
                query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
                List<PlanDesignShareRecord> shareRecords = planDesignShareRecordDao.getListByQuery(query);
                if (Objects.equals(PlanShareEnum.CANCEL_SHARING.getStatus(), planDesignShareRecord.getStatus())) {
                    // 删除方案章节协作用户
                    PlanChapterCollaborateVO planChapterCollaborateVO = new PlanChapterCollaborateVO();
                    planChapterCollaborateVO.setPlanId(plan.getId());
                    planChapterCollaborateVO.setLoginCode(sharedLoginCode);
                    planChapterCollaborateService.deletePlanChapterCollaborateUser(planChapterCollaborateVO);

                    if (!CollectionUtils.isEmpty(shareRecords)) {
                        newPlanDesignShareRecord = shareRecords.get(0);
                        newPlanDesignShareRecord.setStatus(PlanShareEnum.CANCEL_SHARING.getStatus());
                    } else {
                        continue;
                    }
                } else {
                    if (Objects.equals(permission, PlanSharePermissionEnum.READ_ONLY.getFlag())) {
                        // 删除方案章节协作用户
                        PlanChapterCollaborateVO planChapterCollaborateVO = new PlanChapterCollaborateVO();
                        planChapterCollaborateVO.setPlanId(plan.getId());
                        planChapterCollaborateVO.setLoginCode(sharedLoginCode);
                        planChapterCollaborateService.deletePlanChapterCollaborateUser(planChapterCollaborateVO);
                    }

                    if (!CollectionUtils.isEmpty(shareRecords)) {
                        newPlanDesignShareRecord = shareRecords.get(0);
                        if (Objects.equals(permission, newPlanDesignShareRecord.getPermission())) {
                            continue;
                        }
                        newPlanDesignShareRecord.setPermission(permission);
                    } else {
                        newPlanDesignShareRecord.setId(ESUtil.getUUID());
                        newPlanDesignShareRecord.setPlanDesignId(planDesignShareRecord.getPlanDesignId());
                        newPlanDesignShareRecord.setPermission(permission);
                        newPlanDesignShareRecord.setStatus(planDesignShareRecord.getStatus());
                        newPlanDesignShareRecord.setSharedLoginCode(sharedLoginCode);
                        newPlanDesignShareRecord.setOwnerLoginCode(plan.getCreatorCode());
                    }
                    long time = BinaryUtils.getNumberDateTime();
                    newPlanDesignShareRecord.setShareTime(time);
                    newPlanDesignShareRecord.setCreateTime(time);
                    newPlanDesignShareRecord.setModifyTime(time);
                }
                shareRecordList.add(newPlanDesignShareRecord);
            }
            if (!CollectionUtils.isEmpty(shareRecordList)) {
                this.pushNotice(shareRecordList, planDesignShareRecord.getPlanDesignId(), sharedLoginCodes);
                planDesignShareRecordDao.saveOrUpdateBatch(shareRecordList);
            }
        }
        return 1L;
    }

    /**
     *  推送工作台消息
     * @param shareRecordList
     * @param planDesignId
     * @param sharedLoginCodes
     */
    private void pushNotice(List<PlanDesignShareRecord> shareRecordList, Long planDesignId, String[] sharedLoginCodes) {
        //过滤取消分享
        shareRecordList = shareRecordList.stream().filter(shareRecord ->
                shareRecord.getStatus().equals(PlanShareEnum.SHARING.getStatus())).collect(Collectors.toList());
        //过滤掉权限变更消息推送
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planDesignId", planDesignId));
        query.must(QueryBuilders.termsQuery("sharedLoginCode.keyword", sharedLoginCodes));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        List<PlanDesignShareRecord> inshares = planDesignShareRecordDao.getListByQuery(query);
        if (!CollectionUtils.isEmpty(inshares)) {
            Set<String> inShareUserCodes = inshares.stream().map(PlanDesignShareRecord::getSharedLoginCode).collect(Collectors.toSet());
            shareRecordList = shareRecordList.stream().filter(shareRecord ->
                    !inShareUserCodes.contains(shareRecord.getSharedLoginCode())).collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(shareRecordList)) {
            return;
        }
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planDesignId);
        if (planDesignInstance == null) {
            return;
        }
        CSysUser cdt = new CSysUser();
        cdt.setLoginCodes(sharedLoginCodes);
        List<SysUser> shareUsers = userApiSvc.getSysUserByCdt(cdt);
        if (CollectionUtils.isEmpty(shareUsers)) {
            return;
        }
        Map<String, SysUser> userMap = shareUsers.stream().collect(Collectors.toMap(SysUser::getLoginCode, e -> e));
        List<ShareMsgDTO> shareMsgDTOS = new ArrayList<>();
        ShareMsgDTO shareMsgDTO;
        for (PlanDesignShareRecord shareRecord : shareRecordList) {
            if (!userMap.containsKey(shareRecord.getSharedLoginCode())) {
                continue;
            }
            shareMsgDTO = new ShareMsgDTO();
            shareMsgDTO.setDirType(planDesignInstance.getDirType());
            shareMsgDTO.setSourceId(planDesignId.toString());
            shareMsgDTO.setSourceType("plan");
            shareMsgDTO.setOwnerId(SysUtil.getCurrentUserInfo().getId());
            shareMsgDTO.setSharedUserId(userMap.get(shareRecord.getSharedLoginCode()).getId());
            shareMsgDTOS.add(shareMsgDTO);
        }
        String msg = JSON.toJSONString(shareMsgDTOS);
        log.info("推送方案分享工作台消息:{}", msg);
        eamNoticeService.shareMsgSave(shareMsgDTOS);
    }

    private void checkPermission(PlanDesignShareRecord shareRecord, String loginCode, boolean needAuth) {
        Long planId = shareRecord.getPlanDesignId();
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        String planCreatorCode = plan.getCreatorCode();

        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planDesignId", planId));
        query.must(QueryBuilders.termsQuery("sharedLoginCode.keyword", loginCode));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        List<PlanDesignShareRecord> shareList = planDesignShareRecordDao.getListByQuery(query);

        if (needAuth) {
            // 方案的创建用户是当前的操作用户 说明肯定有权限
            if (!loginCode.equals(planCreatorCode) &&
                    (CollectionUtils.isEmpty(shareList)
                            || (!Objects.equals(shareList.get(0).getPermission(), PlanSharePermissionEnum.EDIT_AND_SHARE.getFlag())
                            && !Objects.equals(shareList.get(0).getPermission(), PlanSharePermissionEnum.PUBLISH.getFlag())))) {
                throw new BusinessException(Constants.NO_SHARING_PERMISSION);
            }
            String[] sharedLoginCodes = shareRecord.getSharedLoginCode().split(",");
            if (sharedLoginCodes.length > 0) {
                List<String> sharedLoginCodeList = Arrays.asList(sharedLoginCodes);
                if (sharedLoginCodeList.contains(loginCode)) {
                    throw new BusinessException("方案不能分享给自己!");
                }
            }
        }
    }

    @Override
    public Page<PlanDesignInstance> getMyCoopPlanDesign(PlanDesignInstanceQueryRequest request) {
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        BoolQueryBuilder coopBuilders = QueryBuilders.boolQuery();
        coopBuilders.must(QueryBuilders.termsQuery("sharedLoginCode.keyword", loginCode));
        List<PlanDesignShareRecord> coopList = planDesignShareRecordDao.getListByQuery(coopBuilders);
        if (coopList.isEmpty()) {
            return new Page<>();
        }
        List<Long> coopDesignIds = coopList.stream().map(PlanDesignShareRecord::getPlanDesignId).collect(Collectors.toList());

        if (request.getPageNum() == null) {
            request.setPageNum(1);
        }
        if (request.getPageSize() == null) {
            request.setPageSize(20);
        }

        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        if (StringUtils.isBlank(request.getStatus())) {
            mustNotKeyword(builder, "status", PlanStatusEnum.deleted.name());
        } else {
            mustKeyword(builder, "status", request.getStatus());
        }

        if (request.getTemplateId() != null) {
            builder.must(QueryBuilders.termQuery("templateId", request.getTemplateId()));
        }

        if (request.getTypeId() != null) {
            builder.must(QueryBuilders.termQuery("typeId", request.getTypeId()));
        }

        if (StringUtils.isNotBlank(request.getWord())) {
            builder.must(QueryBuilders.multiMatchQuery(request.getWord(), "name")
                    .operator(Operator.AND).type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
        }
        builder.must(QueryBuilders.termsQuery("id", coopDesignIds));
        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
        return planDesignInstanceDao.getSortListByQuery(request.getPageNum(), request.getPageSize(), builder, sorts);
    }

    /**
     * 方案设计新增时检查名称重复
     *
     * @param name 方案名称
     */
    private void checkNameWhileAdd(Long id, String name, Integer dirType) {
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        if (id != null) {
            builder.mustNot(QueryBuilders.termQuery("id", id));
        }
        builder.must(QueryBuilders.termQuery("name.keyword", name));
        builder.must(QueryBuilders.termQuery("creatorCode.keyword", sysUser.getLoginCode()));
        builder.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.draft.name())));
        builder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        List<PlanDesignInstance> listByQuery = planDesignInstanceDao.getListByQuery(builder);
        if (listByQuery.size() > 0) {
            throw new BusinessException("方案名称已经存在");
        }
    }

    /**
     * 方案设计修改时检查名称重复
     *
     * @param request {@link PlanDesignInstanceUpdateRequest}
     */
    private void checkNameWhileUpdate(PlanDesignInstanceUpdateRequest request, Integer dirType) {
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.termQuery("name.keyword", request.getName()));
        builder.must(QueryBuilders.termQuery("creatorCode.keyword", sysUser.getLoginCode()));
        builder.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.draft.name())));
        builder.mustNot(QueryBuilders.termQuery("id", request.getId()));
        builder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        List<PlanDesignInstance> listByQuery = planDesignInstanceDao.getListByQuery(builder);
        if (!CollectionUtils.isEmpty(listByQuery) && listByQuery.size() > 0) {
            throw new BusinessException("方案名称已经存在");
        }
    }

    private void mustKeyword(BoolQueryBuilder boolQueryBuilder, String key, Object value) {
        boolQueryBuilder.must(QueryBuilders.termQuery(key + ".keyword", value));
    }

    private void mustNotKeyword(BoolQueryBuilder boolQueryBuilder, String key, Object value) {
        boolQueryBuilder.mustNot(QueryBuilders.termQuery(key + ".keyword", value));
    }

    @Override
    public ResponseEntity<byte[]> downLoadAllFile(Long planId) {
        List<PlanChapterVO> chapterList = planChapterInstanceService.getChapterList(planId);
        List<Long> chapterIds = Lists.newArrayList();
        //递归查询出所有章节的id
        findChapterIds(chapterList,chapterIds);
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("id",chapterIds));
        List<ChapterContext> chapterContexts = chapterContextDao.getListByQuery(queryBuilder);
        if (null == chapterContexts || chapterContexts.size() < 1) {
            throw new BinaryException("方案没有章节,不支持下载zip文件包");
        }
        //下面是把方案附件内容块里面的文件拷贝到指定的目录
        try {
            String parentDirPath = mkdirMethod(planId, chapterList, chapterContexts);
            log.info("===============>",parentDirPath);
            PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);

            String planZipName = planDesignInstance.getName() + "-" + CommonUtil.getDateTime(new Date()) + ".zip";
            File outFileUrl = new File(localPath + File.separator + planZipName);
            String result = outFileUrl.getAbsolutePath();
            FileOutputStream fileOutputStream = new FileOutputStream(outFileUrl);
            ZipUtils.toZip(parentDirPath, fileOutputStream, true);
            ZipUtils.delFolder(parentDirPath);
            log.info("最后压缩文件的路径:"+result);
            File file = new File(result);
            ResponseEntity<byte[]> responseEntity = returnRes(file);
            FileUtils.deleteQuietly(file);
            return responseEntity;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private ResponseEntity<byte[]> returnRes(File file) {
        HttpHeaders headers = new HttpHeaders();
        ResponseEntity<byte[]> entity;
        try (InputStream in = new FileInputStream(file)) {
            byte[] bytes = new byte[in.available()];
            int read = in.read(bytes);
            if (read != in.available()) {
                log.info("这块不能直接判断个数,需要等待所有读取完才能比较");
            }
            headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            entity = new ResponseEntity<>(bytes, headers, HttpStatus.OK);
        } catch (Exception e) {
            throw new MessageException(e.getMessage());
        }
        return entity;
    }

    @Override
    public List<PlanDesignInstanceDTO> findAllPlanListForFeign(Long dirId, Integer dirType, String name, Integer publishStatus) {
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
        queryBuilder.must(QueryBuilders.termQuery("dirId", dirId));
        queryBuilder.must(QueryBuilders.termQuery("creatorCode.keyword",currentUserInfo.getLoginCode()));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        if (!StringUtils.isEmpty(name)) {
            queryBuilder.must(QueryBuilders.wildcardQuery("name.keyword","*" + name + "*"));
        }
        if (publishStatus != null) {
            if (Objects.equals(publishStatus, 1)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
            } else if(Objects.equals(publishStatus, 0)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.draft.name()));
            }
        }
        List<PlanDesignInstance> planDesignList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (!CollectionUtils.isEmpty(planDesignList)) {
            /*List<String> businessKeys = planDesignList.stream().filter(plan -> !StringUtils.isEmpty(plan.getBusinessKey()))
                    .map(plan -> plan.getBusinessKey()).collect(Collectors.toList());
            BoolQueryBuilder releaseQuery = QueryBuilders.boolQuery();
            releaseQuery.must(QueryBuilders.termsQuery("businessKey.keyword", businessKeys));
            releaseQuery.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
            List<PlanDesignInstance> releasePlanList = planDesignInstanceDao.getListByQuery(releaseQuery);
            if (!CollectionUtils.isEmpty(releasePlanList)) {
                Set<String> releaseBusinessKeys = releasePlanList.stream().map(plan -> plan.getBusinessKey()).collect(Collectors.toSet());
                if (!CollectionUtils.isEmpty(releaseBusinessKeys)){
                    planDesignList.forEach(plan -> {
                        if (!StringUtils.isEmpty(plan.getBusinessKey()) && releaseBusinessKeys.contains(plan.getBusinessKey())) {
                            plan.setStatus(PlanStatusEnum.published.name());
                        }
                    });
                }
            }*/
           /* if (publishStatus != null) {
                if (Objects.equals(publishStatus, 1)) {
                    planDesignList = planDesignList.stream()
                            .filter(plan -> Objects.equals(plan.getStatus(), PlanStatusEnum.published.name())).collect(Collectors.toList());
                } else if (Objects.equals(publishStatus, 0)) {
                    planDesignList = planDesignList.stream()
                            .filter(plan -> (Objects.equals(plan.getStatus(), PlanStatusEnum.draft.name()) || plan.isProcessApproval())).collect(Collectors.toList());
                }
            }*/
        }
        List<PlanDesignInstanceDTO> collect = planDesignList.stream().map(plan -> {
            PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(plan, planDesignInstanceDTO);
            DlvrTemplateVO dlvrTemplate = deliverableTemplateService.getDlvrTemplateById(plan.getTemplateId());
            if (dlvrTemplate != null && !StringUtils.isEmpty(dlvrTemplate.getTemplateName())) {
                planDesignInstanceDTO.setTemplateName(dlvrTemplate.getTemplateName());
            }

            if (plan.isProcessApproval()) {
                TaskResponse task = flowableService.getCurrentTaskAssignees(String.valueOf(plan.getId()));
                if (task != null) {
                    if (!StringUtils.isEmpty(task.getSubmitter()) && !StringUtils.isEmpty(task.getCurrentAssignees())) {
                        if (!Objects.equals(currentUserInfo.getLoginCode(), task.getSubmitter()) && task.getCurrentAssignees().contains(currentUserInfo.getLoginCode())) {
                            planDesignInstanceDTO.setStatus(PlanStatusEnum.under_approver.name());
                        } else if (Objects.equals(currentUserInfo.getLoginCode(), task.getSubmitter()) && task.getCurrentAssignees().contains(currentUserInfo.getLoginCode())){
                            planDesignInstanceDTO.setStatus(PlanStatusEnum.under_submitter.name());
                        } else if (Objects.equals(currentUserInfo.getLoginCode(), task.getSubmitter()) && !task.getCurrentAssignees().contains(currentUserInfo.getLoginCode())){
                            planDesignInstanceDTO.setStatus(PlanStatusEnum.under_approver.name());
                        }
                    }
                }
            }
            return planDesignInstanceDTO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public List<PlanDesignInstanceDTO> findAllPlanList(String name, Integer publishStatus) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        if (!StringUtils.isEmpty(name)) {
            queryBuilder.must(QueryBuilders.wildcardQuery("name.keyword","*" + name + "*"));
        }
        if (publishStatus != null) {
            if (Objects.equals(publishStatus, 1)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
            } else if(Objects.equals(publishStatus, 0)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.draft.name()));
            }
        }
        List<PlanDesignInstance> planDesignList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (CollectionUtils.isEmpty(planDesignList)) {
            return new ArrayList<>();
        }
        List<PlanDesignInstanceDTO> collect = planDesignList.stream().map(plan -> {
            PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(plan, planDesignInstanceDTO);
            DlvrTemplateVO dlvrTemplate = deliverableTemplateService.getDlvrTemplateById(plan.getTemplateId());
            if (dlvrTemplate != null && !StringUtils.isEmpty(dlvrTemplate.getTemplateName())) {
                planDesignInstanceDTO.setTemplateName(dlvrTemplate.getTemplateName());
            }
            return planDesignInstanceDTO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public Page<PlanInfoVO> findDiagramPlanList(Integer pageNum, Integer pageSize, String diagramId, Integer type) {
        if (StringUtils.isEmpty(diagramId)) {
            throw new BusinessException("视图主键不能为空!");
        }
        if (type == null) {
            throw new BusinessException("视图类型不能为空!");
        }
        PlanArtifact planArtifact = new PlanArtifact();
        if (Objects.equals(type, 0)) {
            planArtifact.setDiagramId(diagramId);
        } else {
            planArtifact.setReleaseDiagramId(diagramId);
        }
        List<PlanArtifact> planArtifactList = planArtifactService.findPlanArtifactList(planArtifact);
        if (!CollectionUtils.isEmpty(planArtifactList)) {
            Set<Long> planIdList = planArtifactList.stream().map(planArtifactInfo -> planArtifactInfo.getPlanId()).collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(planIdList)) {
                BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                queryBuilder.must(QueryBuilders.termsQuery("id", planIdList));
                queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
                Page<PlanDesignInstance> page = planDesignInstanceDao.getSortListByQuery(pageNum, pageSize, queryBuilder, "modifyTime", false);
                if (page != null && !CollectionUtils.isEmpty(page.getData())) {
                    List<PlanInfoVO> planList = new ArrayList<>();
                    page.getData().stream().forEach(plan -> {
                        PlanInfoVO planInfoVO = new PlanInfoVO();
                        planInfoVO.setId(plan.getId());
                        planInfoVO.setName(plan.getName());
                        TemplateType templateType = templateTypeDao.getById(plan.getTypeId());
                        if (templateType != null && !StringUtils.isEmpty(templateType.getTypeName())) {
                            planInfoVO.setType(templateType.getTypeName());
                        }
                        PlanArtifact artifact = new PlanArtifact();
                        if (Objects.equals(type, 0)) {
                            artifact.setDiagramId(diagramId);
                        } else {
                            artifact.setReleaseDiagramId(diagramId);
                        }
                        artifact.setPlanId(plan.getId());
                        List<PlanArtifact> artifactList = planArtifactService.findPlanArtifactList(artifact);
                        if (!CollectionUtils.isEmpty(artifactList)) {
                            if (artifactList.size() > 1) {
                                PlanArtifact newPlanArtifact = artifactList.stream().max((a, b) -> a.getVersion() - b.getVersion()).get();
                                planInfoVO.setDiagramVersion("v" + newPlanArtifact.getVersion());
                            } else {
                                planInfoVO.setDiagramVersion("v" + artifactList.get(0).getVersion());
                            }
                        }
                        CSysUser cdt = new CSysUser();
                        cdt.setLoginCodeEqual(plan.getCreatorCode());
                        List<SysUser> sysUserList = userApiSvc.getSysUserByCdt(cdt);
                        if (!CollectionUtils.isEmpty(sysUserList)) {
                            SysUser sysUser = sysUserList.get(0);
                            planInfoVO.setCreatorName(sysUser.getUserName());
                        } else {
                            planInfoVO.setCreatorName(plan.getCreatorName());
                        }
                        planInfoVO.setModifyTime(plan.getModifyTime());
                        planInfoVO.setStatus(plan.getStatus());
                        if (!StringUtils.isEmpty(plan.getBusinessKey())) {
                            BoolQueryBuilder query = QueryBuilders.boolQuery();
                            query.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
                            query.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
                            List<PlanDesignInstance> historyPlanList = planDesignInstanceDao.getListByQuery(query);
                            if (!CollectionUtils.isEmpty(historyPlanList)) {
                                List<Long> collect = historyPlanList.stream().sorted((o1, o2) -> o1.getModifyTime().compareTo(o2.getModifyTime()))
                                        .map(planInfo -> planInfo.getId()).collect(Collectors.toList());
                                int i = collect.indexOf(plan.getId()) + 1;
                                planInfoVO.setPlanVersion("v" + i);
                            }
                        }
                        planList.add(planInfoVO);
                    });
                    return new Page<>(pageNum, pageSize, page.getTotalRows(), page.getTotalPages(), planList);
                }
            }
        }
        return new Page<>(0, 0, 0, 0, Collections.EMPTY_LIST);
    }

    @Override
    public Page<PlanDesignInstance> findPlanInstanceList(String businessKey, List<String> statusList, Integer dirType) {
        if (StringUtils.isEmpty(businessKey)) {
            return new Page<>(0, 0, 0, 0, Collections.EMPTY_LIST);
        }
        if (CollectionUtils.isEmpty(statusList)) {
            return new Page<>(0, 0, 0, 0, Collections.EMPTY_LIST);
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("businessKey.keyword", businessKey));
        query.must(QueryBuilders.termsQuery("status.keyword", statusList));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        return planDesignInstanceDao.getSortListByQuery(1, 3000, query, "createTime", false);
    }

    @Override
    public PlanDesignInstance getPlanDesignInstance(Long planId) {
        if (planId == null) {
            return null;
        }
        return planDesignInstanceDao.getById(planId);
    }


    public JSONObject detectionPlan_old(DetectionPlanVo detectionPlanVo, SysUser sysUser) {
        if (detectionPlanVo == null) {
            throw new BusinessException("参数不能为空!");
        }
        if (detectionPlanVo.getPlanId() == null) {
            throw new BusinessException("方案参数错误!");
        }
        if (detectionPlanVo.getDirId() == null) {
            throw new BusinessException("检出位置不能为空!");
        }
        if (StringUtils.isEmpty(detectionPlanVo.getName())) {
            throw new BusinessException("检出方案名称不能为空!");
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(detectionPlanVo.getPlanId());
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        // 验证是否同名
        checkNameWhileAdd(null, detectionPlanVo.getName(), detectionPlanVo.getDirType());

        // 排除根路径
        if (!detectionPlanVo.getDirId().equals(0L)) {
            EamCategory category = categorySvc.getById(detectionPlanVo.getDirId(), LibType.PRIVATE);
            if (category == null || category.getDataStatus().equals(Constants.DELETED_STATUS)) {
                throw new BusinessException("检出的位置已被删除!");
            }
        }

        UserInfo userInfo = null;
        try {
            userInfo = userApiSvc.getUserInfoByLoginCode(sysUser.getLoginCode());
        } catch (Exception e) {
            throw new BusinessException("当前用户已被删除!");
        }
        if (userInfo == null) {
            throw new BusinessException("获取用户信息错误!");
        }

        PlanDesignInstance planDesignInstance = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, planDesignInstance);
        planDesignInstance.setStatus(PlanStatusEnum.draft.name());
        planDesignInstance.setAssetsType(Constants.DESIGN);
        planDesignInstance.setDetectionPlanId(detectionPlanVo.getPlanId());
        planDesignInstance.setDirId(detectionPlanVo.getDirId());
//        planDesignInstance.setDirType(detectionPlanVo.getDirType());
        planDesignInstance.setProcessApproval(false);
        planDesignInstance.setName(detectionPlanVo.getName());
        String secret = detectionPlanVo.getName();
        if (!StringUtils.isEmpty(planDesignInstance.getDefaultSystemCiCode())) {
            secret = secret + planDesignInstance.getDefaultSystemCiCode();
        }
        String businessKey = SecureUtil.md5(secret);
        planDesignInstance.setBusinessKey(businessKey);
        // 封装方案的CCUU
        handlerPlanCCUU(planDesignInstance, userInfo);
        Long newPlanId = planDesignInstanceDao.saveOrUpdate(planDesignInstance);
        PlanDesignInstance newPlan = planDesignInstanceDao.getById(newPlanId);
        //设置发布路径
        newPlan.setAssetsDirId(null);
        planInstanceServiceExtend.getPlanReleaseDirInfo(newPlan);
        // 2.2 新增章节
        List<ChapterInstance> chapterInstanceList = planChapterInstanceService.findChapterInstanceList(plan.getId(), null);
        if (!CollectionUtils.isEmpty(chapterInstanceList)) {
            Map<Long, Long> map = new HashMap<>();
            chapterInstanceList.forEach(chapterInstance -> {
                long chapterId = ESUtil.getUUID();
                map.put(chapterInstance.getId(), chapterId);
            });

            List<ChapterInstance> newChapterInstanceList = new ArrayList<>();
            List<ChapterContext> newChapterContextList = new ArrayList<>();
            List<PlanArtifact> newPlanArtifactList = new ArrayList<>();
            UserInfo finalUserInfo = userInfo;
            chapterInstanceList.forEach(chapterInstance -> {
                ChapterInstance newChapterInstance = new ChapterInstance();
                BeanUtils.copyProperties(chapterInstance, newChapterInstance);
                newChapterInstance.setId(map.get(chapterInstance.getId()));
                newChapterInstance.setPlanId(newPlanId);
                newChapterInstance.setStatus(Constants.DRAFT);
                if (!Objects.equals(chapterInstance.getParentId(), 0L)) {
                    newChapterInstance.setParentId(map.get(chapterInstance.getParentId()));
                }
                // 封装章节的CCUU
                handlerChapterCCUU(newChapterInstance, finalUserInfo);
                newChapterInstanceList.add(newChapterInstance);

                BoolQueryBuilder contextQuery = QueryBuilders.boolQuery();
                contextQuery.must(QueryBuilders.termQuery("id", chapterInstance.getId()));
                List<ChapterContext> chapterContextList = chapterContextDao.getListByQuery(contextQuery);
                if (!CollectionUtils.isEmpty(chapterContextList)) {
                    chapterContextList.forEach(context -> {
                        ChapterContext newChapterContext = new ChapterContext();
                        BeanUtils.copyProperties(context, newChapterContext);
                        newChapterContext.setId(newChapterInstance.getId());
                        newChapterContext.setPlanId(newPlanId);
                        newChapterContext.setStatus(Constants.DRAFT);
                        newChapterContextList.add(newChapterContext);
                    });
                }

                // 复制方案关联的视图
                PlanArtifact planArtifact = new PlanArtifact();
                planArtifact.setPlanId(plan.getId());
                planArtifact.setChapterId(chapterInstance.getId());
                planArtifact.setStatus(1);
                List<PlanArtifact> planArtifactList = planArtifactService.findPlanArtifactList(planArtifact);
                if (!CollectionUtils.isEmpty(planArtifactList)) {
                    planArtifactList.forEach(planArtifactInfo -> {

                        PlanArtifact newPlanArtifact = new PlanArtifact();
                        newPlanArtifact.setPlanId(newPlanId);
                        newPlanArtifact.setChapterId(newChapterInstance.getId());
                        newPlanArtifact.setModuleId(planArtifactInfo.getModuleId());
                        newPlanArtifact.setDiagramId(planArtifactInfo.getDiagramId());
                        List<PlanArtifact> artifactList = planArtifactService.findPlanArtifactList(planArtifact);

                        if (!CollectionUtils.isEmpty(artifactList)) {
                            PlanArtifact artifact = artifactList.get(0);
                            newPlanArtifact.setReleaseDiagramId(artifact.getReleaseDiagramId());
                            newPlanArtifact.setVersion(artifact.getVersion());
                        } else {
                            Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(planArtifactInfo.getDiagramId());
                            if (diagramId == null) {
                                throw new BusinessException("获取视图信息错误!");
                            }
                            ESDiagram diagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                            if (diagram != null) {
                                // 缩略图
                                String icon1 = diagram.getIcon1();
                                if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                    icon1 = httpResouceUrl + icon1;
                                    diagram.setIcon1(icon1);
                                }
                            }
                            if (diagram != null && Objects.equals(diagram.getIsOpen(), 1)) {
                                newPlanArtifact.setReleaseDiagramId(diagram.getDEnergy());
                                newPlanArtifact.setVersion(diagram.getReleaseVersion());
                            }
                        }
                        newPlanArtifact.setDiagramProductType(planArtifactInfo.getDiagramProductType());
                        newPlanArtifact.setStatus(1);
                        // 封装制品的CCUU
                        handlerArtifactCCUU(newPlanArtifact, finalUserInfo);
                        newPlanArtifactList.add(newPlanArtifact);
                    });
                }
            });
            planChapterInstanceService.saveOrUpdateBatch(newChapterInstanceList);
            // 2.3 新增模块数据
            chapterContextDao.saveOrUpdateBatch(newChapterContextList);
            // 2.4 新增方案关联视图信息
            planArtifactService.savePlanArtifact(newPlanArtifactList);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", newPlanId);
        return jsonObject;
    }

    @Override
    public JSONObject detectionPlan(DetectionPlanVo detectionPlanVo, SysUser sysUser) {
        if (detectionPlanVo == null) {
            throw new BusinessException("参数不能为空!");
        }
        if (detectionPlanVo.getPlanId() == null) {
            throw new BusinessException("方案参数错误!");
        }
        if (detectionPlanVo.getDirId() == null) {
            throw new BusinessException("检出位置不能为空!");
        }
        if (StringUtils.isEmpty(detectionPlanVo.getName())) {
            throw new BusinessException("检出方案名称不能为空!");
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(detectionPlanVo.getPlanId());
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        // 验证是否同名
        checkNameWhileAdd(null, detectionPlanVo.getName(), detectionPlanVo.getDirType());

        // 排除根路径
        if (!detectionPlanVo.getDirId().equals(0L)) {
            EamCategory category = categorySvc.getById(detectionPlanVo.getDirId(), LibType.PRIVATE);
            if (category == null || category.getDataStatus().equals(Constants.DELETED_STATUS)) {
                throw new BusinessException("检出的位置已被删除!");
            }
        }

        UserInfo userInfo = null;
        try {
            userInfo = userApiSvc.getUserInfoByLoginCode(sysUser.getLoginCode());
        } catch (Exception e) {
            throw new BusinessException("当前用户已被删除!");
        }
        if (userInfo == null) {
            throw new BusinessException("获取用户信息错误!");
        }

        PlanDesignInstance planDesignInstance = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, planDesignInstance);
        planDesignInstance.setStatus(PlanStatusEnum.draft.name());
        planDesignInstance.setAssetsType(Constants.DESIGN);
        planDesignInstance.setDetectionPlanId(detectionPlanVo.getPlanId());
        planDesignInstance.setDirId(detectionPlanVo.getDirId());
//        planDesignInstance.setDirType(detectionPlanVo.getDirType());
        planDesignInstance.setProcessApproval(false);
        planDesignInstance.setName(detectionPlanVo.getName());
        // region 支持修改关联资产
        if (!StringUtils.isEmpty(detectionPlanVo.getDefaultSystemCiCode())) {
            planDesignInstance.setDefaultSystemCiCode(detectionPlanVo.getDefaultSystemCiCode());
            planDesignInstance.setEchoDirName(detectionPlanVo.getEchoDirName());
            planDesignInstance.setAssetsDirId(detectionPlanVo.getDirId());
            List<String> ciCodeList = Arrays.asList(detectionPlanVo.getDefaultSystemCiCode());
            planDesignInstance.setCiCodeList(ciCodeList);
            planDesignInstance.setIsCurrentVersion(true);
            planDesignInstance.setRecyclable(true);
        }
        //endregion
        String secret = detectionPlanVo.getName();
        if (!StringUtils.isEmpty(planDesignInstance.getDefaultSystemCiCode())) {
            secret = secret + planDesignInstance.getDefaultSystemCiCode();
        }
        String businessKey = SecureUtil.md5(secret);
        planDesignInstance.setBusinessKey(businessKey);
        // 封装方案的CCUU
        handlerPlanCCUU(planDesignInstance, userInfo);
        Long newPlanId = planDesignInstanceDao.saveOrUpdate(planDesignInstance);
        PlanDesignInstance newPlan = planDesignInstanceDao.getById(newPlanId);
        //设置发布路径
        newPlan.setAssetsDirId(null);
        planInstanceServiceExtend.getPlanReleaseDirInfo(newPlan);
        // 2.2 新增章节
        List<ChapterInstance> chapterInstanceList = planChapterInstanceService.findChapterInstanceList(plan.getId(), null);
        if (!CollectionUtils.isEmpty(chapterInstanceList)) {
            Map<Long, Long> map = new HashMap<>();
            chapterInstanceList.forEach(chapterInstance -> {
                long chapterId = ESUtil.getUUID();
                map.put(chapterInstance.getId(), chapterId);
            });

            List<ChapterInstance> newChapterInstanceList = new ArrayList<>();
            List<ChapterContext> newChapterContextList = new ArrayList<>();
            List<PlanArtifact> newPlanArtifactList = new ArrayList<>();
            UserInfo finalUserInfo = userInfo;
            chapterInstanceList.forEach(chapterInstance -> {
                ChapterInstance newChapterInstance = new ChapterInstance();
                BeanUtils.copyProperties(chapterInstance, newChapterInstance);
                newChapterInstance.setId(map.get(chapterInstance.getId()));
                newChapterInstance.setPlanId(newPlanId);
                newChapterInstance.setStatus(Constants.DRAFT);
                if (!Objects.equals(chapterInstance.getParentId(), 0L)) {
                    newChapterInstance.setParentId(map.get(chapterInstance.getParentId()));
                }
                // 封装章节的CCUU
                handlerChapterCCUU(newChapterInstance, finalUserInfo);
                newChapterInstanceList.add(newChapterInstance);

                BoolQueryBuilder contextQuery = QueryBuilders.boolQuery();
                contextQuery.must(QueryBuilders.termQuery("id", chapterInstance.getId()));
                List<ChapterContext> chapterContextList = chapterContextDao.getListByQuery(contextQuery);
                if (!CollectionUtils.isEmpty(chapterContextList)) {
                    chapterContextList.forEach(context -> {
                        ChapterContext newChapterContext = new ChapterContext();
                        BeanUtils.copyProperties(context, newChapterContext);
                        newChapterContext.setId(newChapterInstance.getId());
                        newChapterContext.setPlanId(newPlanId);
                        newChapterContext.setStatus(Constants.DRAFT);
                        newChapterContextList.add(newChapterContext);
                    });
                }

                // 复制方案关联的视图
                PlanArtifact planArtifact = new PlanArtifact();
                planArtifact.setPlanId(plan.getId());
                planArtifact.setChapterId(chapterInstance.getId());
                planArtifact.setStatus(1);
                List<PlanArtifact> planArtifactList = planArtifactService.findPlanArtifactList(planArtifact);
                if (!CollectionUtils.isEmpty(planArtifactList)) {
                    planArtifactList.forEach(planArtifactInfo -> {

                        PlanArtifact newPlanArtifact = new PlanArtifact();
                        newPlanArtifact.setPlanId(newPlanId);
                        newPlanArtifact.setChapterId(newChapterInstance.getId());
                        newPlanArtifact.setModuleId(planArtifactInfo.getModuleId());
                        newPlanArtifact.setDiagramId(planArtifactInfo.getDiagramId());
                        List<PlanArtifact> artifactList = planArtifactService.findPlanArtifactList(planArtifact);

                        if (!CollectionUtils.isEmpty(artifactList)) {
                            PlanArtifact artifact = artifactList.get(0);
                            newPlanArtifact.setReleaseDiagramId(artifact.getReleaseDiagramId());
                            newPlanArtifact.setVersion(artifact.getVersion());
                        } else {
                            Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(planArtifactInfo.getDiagramId());
                            if (diagramId == null) {
                                throw new BusinessException("获取视图信息错误!");
                            }
                            ESDiagram diagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                            if (diagram != null) {
                                // 缩略图
                                String icon1 = diagram.getIcon1();
                                if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                    icon1 = httpResouceUrl + icon1;
                                    diagram.setIcon1(icon1);
                                }
                            }
                            if (diagram != null && Objects.equals(diagram.getIsOpen(), 1)) {
                                newPlanArtifact.setReleaseDiagramId(diagram.getDEnergy());
                                newPlanArtifact.setVersion(diagram.getReleaseVersion());
                            }
                        }
                        newPlanArtifact.setDiagramProductType(planArtifactInfo.getDiagramProductType());
                        newPlanArtifact.setStatus(1);
                        // 封装制品的CCUU
                        handlerArtifactCCUU(newPlanArtifact, finalUserInfo);
                        newPlanArtifactList.add(newPlanArtifact);
                    });
                }
            });
            planChapterInstanceService.saveOrUpdateBatch(newChapterInstanceList);
            // 2.3 新增模块数据
            chapterContextDao.saveOrUpdateBatch(newChapterContextList);
            // 2.4 新增方案关联视图信息
            planArtifactService.savePlanArtifact(newPlanArtifactList);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", newPlanId);
        return jsonObject;
    }

    @Override
    public List<PlanHistoryVersionVo> findPlanHistoryVersionList(Long planId) {
        if (planId == null) {
            throw new BusinessException("参数不能为空!");
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        if (StringUtils.isEmpty(plan.getBusinessKey())) {
            return Collections.emptyList();
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
        queryBuilder.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        Page<PlanDesignInstance> planDesignInstancePage = planDesignInstanceDao.getSortListByQuery(1, 3000, queryBuilder, "createTime", false);
        if (planDesignInstancePage != null && !CollectionUtils.isEmpty(planDesignInstancePage.getData())) {
            List<PlanDesignInstance> data = planDesignInstancePage.getData();
            List<PlanHistoryVersionVo> planHistoryVersionList = new ArrayList<>(data.size());
            for(int i = 0 ; i< data.size(); i++) {
                PlanDesignInstance planDesignInstance = data.get(i);
                PlanHistoryVersionVo planHistoryVersionVo = new PlanHistoryVersionVo();
                planHistoryVersionVo.setId(planDesignInstance.getId());
                planHistoryVersionVo.setName(planDesignInstance.getName());
                CSysUser cdt = new CSysUser();
                cdt.setLoginCodeEqual(planDesignInstance.getCreatorCode());
                List<SysUser> sysUserList = userApiSvc.getSysUserByCdt(cdt);
                if (!CollectionUtils.isEmpty(sysUserList)) {
                    SysUser sysUser = sysUserList.get(0);
                    planHistoryVersionVo.setCreator(sysUser.getUserName());
                } else {
                    planHistoryVersionVo.setCreator(planDesignInstance.getCreatorName());
                }
                planHistoryVersionVo.setPublishTime(planDesignInstance.getCreateTime());
                Integer sign = data.size() - i;
                planHistoryVersionVo.setVersion("V" + sign);
                planHistoryVersionList.add(planHistoryVersionVo);
            }
            return planHistoryVersionList;
        }
        return Collections.emptyList();
    }

    @Override
    public Map<String, List<PlanDesignInstance>> findPlanHistoryVersionListByIds(List<Long> planIds) {
        if (CollectionUtils.isEmpty(planIds)) {
            return Collections.emptyMap();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("id", planIds));
        List<PlanDesignInstance> listByQuery = planDesignInstanceDao.getListByQuery(query);
        List<String> businessKey = listByQuery.stream().filter(e -> !BinaryUtils.isEmpty(e.getBusinessKey()))
                .map(planDesignInstance -> planDesignInstance.getBusinessKey()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(businessKey)) {
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termsQuery("businessKey.keyword", businessKey));
            queryBuilder.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
            queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
            Page<PlanDesignInstance> planDesignInstancePage = planDesignInstanceDao.getSortListByQuery(1, 3000, queryBuilder, "createTime", false);
            if (planDesignInstancePage != null && !CollectionUtils.isEmpty(planDesignInstancePage.getData())) {
                List<PlanDesignInstance> data = planDesignInstancePage.getData();
                Map<String, List<PlanDesignInstance>> map = data.stream().collect(Collectors.groupingBy(planDesignInstance -> planDesignInstance.getBusinessKey()));
                return map;
            }
        }
        return Collections.emptyMap();
    }

    @Override
    public List<PlanDesignInstance> findAllPlanDesignListByPlanIds(Long[] planIds, String name) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("id", planIds));
        queryBuilder.mustNot(QueryBuilders.termsQuery("status.keyword", "deleted"));
        List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (planDesignInstanceList == null || planDesignInstanceList.size() <= 0) {
            return new ArrayList<>();
        }
        if (!StringUtils.isBlank(name)) {
            return planDesignInstanceList.stream().filter(item -> Pattern.compile(Pattern.quote(name), Pattern.CASE_INSENSITIVE).matcher(item.getName()).find()).collect(Collectors.toList());
        }else{
            return planDesignInstanceList;
        }
    }

    @Override
    public PlanHistoryVersionVo getPlanLatestVersion(Long planId, Integer type) {
        if (planId == null) {
            throw new BusinessException("参数不能为空!");
        }
        if (type == null) {
            throw new BusinessException("类型不能为空!");
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
        queryBuilder.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        List<PlanDesignInstance> planVersionList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (!CollectionUtils.isEmpty(planVersionList)) {
            PlanDesignInstance planInfo = null;
            for (PlanDesignInstance planDesignInstance : planVersionList) {
                if (Objects.equals(planDesignInstance.getStatus(), PlanStatusEnum.published.name())) {
                    planInfo = planDesignInstance;
                    break;
                }
            }

            if (planInfo != null) {
                if (Objects.equals(type, 2)
                        || (Objects.equals(type, 1) && !Objects.equals(plan.getDetectionPlanId(), planInfo.getId()))) {
                    return getPlanHistoryVersion(planInfo, planVersionList);
                }
            }
        }
        return new PlanHistoryVersionVo(false);
    }

    @Override
    public List<PlanDesignInstanceDTO> findRenewVersionPlanList(Long planId) {
        if (planId == null){
            return Collections.emptyList();
        }
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        if (plan == null) {
            throw new BusinessException("方案已删除!");
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("businessKey.keyword", plan.getBusinessKey()));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        queryBuilder.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
        List<PlanDesignInstance> planVersionList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (!CollectionUtils.isEmpty(planVersionList)) {
            List<PlanDesignInstanceDTO> newPlanList = new ArrayList<>();
            planVersionList.forEach(instance -> {
                PlanDesignInstanceDTO planDto = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(instance, planDto);
                newPlanList.add(planDto);
            });
            return newPlanList;
        }
        return Collections.emptyList();
    }

    @Override
    public List<PlanDesignInstanceDTO> findDesignHistoryPlanList(List<Long> historyPlanIds) {
        if (CollectionUtils.isEmpty(historyPlanIds)) {
            return Collections.emptyList();
        }
        List<PlanDesignInstanceDTO> data = new ArrayList<>();
        for (Long historyPlanId : historyPlanIds) {
            PlanDesignInstance plan = planDesignInstanceDao.getById(historyPlanId);
            if (plan == null) {
                continue;
            }
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termQuery("detectionPlanId", plan.getId()));
            queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
            queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
            List<PlanDesignInstance> planVersionList = planDesignInstanceDao.getListByQuery(queryBuilder);
            if (!CollectionUtils.isEmpty(planVersionList)) {
                planVersionList.forEach(planInfo -> {
                    PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
                    BeanUtils.copyProperties(planInfo, planDesignInstanceDTO);
                    data.add(planDesignInstanceDTO);
                });
            }
        }
        return data;
    }

    @Override
    public PlanDesignInstanceDTO getAssetsLatestPlan(String businessKey, Integer dirType) {
        if (StringUtils.isEmpty(businessKey)) {
            return null;
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("businessKey.keyword", businessKey));
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
        List<PlanDesignInstance> planVersionList = planDesignInstanceDao.getListByQuery(queryBuilder);
        if (!CollectionUtils.isEmpty(planVersionList)) {
            PlanDesignInstance planDesignInstance = planVersionList.get(0);
            PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(planDesignInstance, planDesignInstanceDTO);
            return planDesignInstanceDTO;
        }
        return null;
    }

    @Override
    public List<PlanDesignInstanceDTO> findAssetsLatestPlanList(List<PlanVersionDTO> planVersionList) {
        if (CollectionUtils.isEmpty(planVersionList)) {
            return Collections.emptyList();
        }
        List<PlanDesignInstanceDTO> planDesignInstanceList = new ArrayList<>();
        for (PlanVersionDTO planVersionDTO : planVersionList) {
            PlanDesignInstanceDTO assetsLatestPlan = getAssetsLatestPlan(planVersionDTO.getBusinessKey(), planVersionDTO.getDirType());
            if (assetsLatestPlan != null) {
                planDesignInstanceList.add(assetsLatestPlan);
            }
        }
        return planDesignInstanceList;
    }

    private PlanHistoryVersionVo getPlanHistoryVersion(PlanDesignInstance planInfo, List<PlanDesignInstance> planVersionList) {
        PlanHistoryVersionVo planHistoryVersionVo = new PlanHistoryVersionVo();
        planHistoryVersionVo.setId(planInfo.getId());
        planHistoryVersionVo.setName(planInfo.getName());
        planHistoryVersionVo.setCreator(planInfo.getCreatorName());
        planHistoryVersionVo.setPublishTime(planInfo.getCreateTime());
        planHistoryVersionVo.setVersion("V" + planVersionList.size());
        planHistoryVersionVo.setDirType(planInfo.getDirType());
        planHistoryVersionVo.setStatus(true);
        return planHistoryVersionVo;
    }

    private String mkdirMethod(Long planId, List<PlanChapterVO> chapterList, List<ChapterContext> chapterContexts) throws IOException {
        Long dateTimeFolder = ESUtil.getUUID();
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
        File destFolder = new File(localPath+File.separator+dateTimeFolder+File.separator + planDesignInstance.getName());
        if(!destFolder.exists()){
            destFolder.mkdirs();
        }
        String parentDirPath = destFolder.getAbsolutePath();
        Map<Long, ChapterContext> chapterContextMap = chapterContexts.stream().collect(Collectors.toMap(item -> item.getId(), item -> item));
        for (PlanChapterVO planChapterVO : chapterList) {
            recursionMkdirAndFile(Collections.singletonList(planChapterVO),chapterContextMap,parentDirPath);
        }
        log.info("================parentDirPath============="+parentDirPath);
        return destFolder.getAbsolutePath();
    }

    private void recursionMkdirAndFile(List<PlanChapterVO> chapterList,  Map<Long, ChapterContext> chapterContextMap, String parentDirPath) throws IOException {
        if (null == chapterList || chapterList.size() < 1) {
            return;
        }
        for (PlanChapterVO planChapterVO : chapterList) {
            String destFolderPath = parentDirPath + File.separator +  planChapterVO.getName();
            ChapterContext chapterContext = chapterContextMap.get(planChapterVO.getId());
            List<ContextModule> moduleList = chapterContext.getModuleList();
            List<ContextModule> fileContext = moduleList.stream().filter(item -> item.getModuleDefinition().getType().equals(5)).collect(Collectors.toList());
            for (ContextModule contextModule : fileContext) {
                JSONObject jsonObject = JSON.parseObject(contextModule.getData());
                JSONArray arrayData = jsonObject.getJSONArray("data");
                if (arrayData == null) {
                    continue;
                }
                List<ContextFileVo> contextFileVos = arrayData.toJavaList(ContextFileVo.class);
                for (ContextFileVo contextFileVo : contextFileVos) {
                    String replace = contextFileVo.getResourcePath().replace(httpPath, "");
                    String filePath = localPath + replace;
                    //String filePath = "D:\\fileupload\\AAa.docx";
                    rsmUtils.downloadRsmAndUpdateLocalRsm(filePath);
                    File sourceFile = new File(filePath);
                    ZipUtils.copyFileUsingFileChannels(sourceFile,new File(destFolderPath,contextFileVo.getResourceName()+ "." + contextFileVo.getResourceType()));
                }
            }
            recursionMkdirAndFile(planChapterVO.getChildChapterList(),chapterContextMap,destFolderPath);
        }
    }

    private void findChapterIds(List<PlanChapterVO> chapterList, List<Long> chapterIds) {
        if (null == chapterList || chapterList.size() < 1) {
            return;
        }
        for (PlanChapterVO planChapterVO : chapterList) {
            chapterIds.add(planChapterVO.getId());
            List<PlanChapterVO> childChapterList = planChapterVO.getChildChapterList();
            findChapterIds(childChapterList,chapterIds);
        }
    }

    /**
     * 方案的CCUU
     * @param planDesignInstance
     * @param userInfo
     */
    private void handlerPlanCCUU(PlanDesignInstance planDesignInstance, UserInfo userInfo) {
        planDesignInstance.setId(ESUtil.getUUID());
        planDesignInstance.setCreatorCode(userInfo.getLoginCode());
        planDesignInstance.setCreatorName(userInfo.getUserName());
        planDesignInstance.setCreateTime(ESUtil.getNumberDateTime());
        planDesignInstance.setModifyTime(ESUtil.getNumberDateTime());
        planDesignInstance.setModifierCode(userInfo.getLoginCode());
        planDesignInstance.setModifierName(userInfo.getUserName());
    }

    /**
     * 封装章节的CCUU
     * @param newChapterInstance
     * @param userInfo
     */
    private void handlerChapterCCUU(ChapterInstance newChapterInstance, UserInfo userInfo) {
        newChapterInstance.setCreatorCode(userInfo.getLoginCode());
        newChapterInstance.setCreatorName(userInfo.getUserName());
        newChapterInstance.setCreateTime(ESUtil.getNumberDateTime());
        newChapterInstance.setModifyTime(ESUtil.getNumberDateTime());
        newChapterInstance.setModifierCode(userInfo.getLoginCode());
        newChapterInstance.setModifierName(userInfo.getUserName());
    }

    /**
     * 封装制品的CCUU
     * @param newPlanArtifact
     * @param userInfo
     */
    private void handlerArtifactCCUU(PlanArtifact newPlanArtifact, UserInfo userInfo) {
        newPlanArtifact.setId(ESUtil.getUUID());
        newPlanArtifact.setCreatorCode(userInfo.getLoginCode());
        newPlanArtifact.setCreatorName(userInfo.getUserName());
        newPlanArtifact.setCreateTime(ESUtil.getNumberDateTime());
        newPlanArtifact.setModifyTime(ESUtil.getNumberDateTime());
        newPlanArtifact.setModifierCode(userInfo.getLoginCode());
        newPlanArtifact.setModifierName(userInfo.getUserName());
    }

    @Override
    public List<PlanDesignShareRecordDTO> findShareRecordList(Long planId) {
        if (planId == null) {
            return new ArrayList<>();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planDesignId", planId));
        query.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        List<PlanDesignShareRecord> records = planDesignShareRecordDao.getListByQuery(query);
        List<PlanDesignShareRecordDTO> designShareRecordDTOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(records)) {
            for (PlanDesignShareRecord shareRecord : records) {
                PlanDesignShareRecordDTO shareRecordDTO = new PlanDesignShareRecordDTO();
                BeanUtils.copyProperties(shareRecord, shareRecordDTO);
                designShareRecordDTOS.add(shareRecordDTO);
            }
        }
        return designShareRecordDTOS;
    }

    @Override
    public List<PlanDesignInstanceDTO> findByTemplateId(Long templateId) {
        if (templateId == null) {
            return new ArrayList<>();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery(Constants.TEMPLATE_ID_STRING, templateId));
        query.mustNot(QueryBuilders.termsQuery("status.keyword", PlanStatusEnum.deleted.name(), PlanStatusEnum.history.name()));
        List<PlanDesignInstance> instances = planDesignInstanceDao.getListByQuery(query);
        List<PlanDesignInstanceDTO> instanceDTOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(instances)) {
            for (PlanDesignInstance instance : instances) {
                PlanDesignInstanceDTO instanceDTO = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(instance, instanceDTO);
                instanceDTOS.add(instanceDTO);
            }
        }
        return instanceDTOS;
    }

    @Override
    public String exportPlan(HttpServletResponse response, Long planId) {
        // 方案数据
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案错误!");
        }
        XWPFDocument document = this.getWord(planDesignInstance, null);
        OutputStream out = null;
        try {
            // TODO 导出到本地
            /*response.setHeader(HttpHeaders.PRAGMA, "No-cache");
            response.setHeader(HttpHeaders.CACHE_CONTROL, "No-cache");
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8");
            //配置导出的word名称&后缀
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(planDesignInstance.getName() + ".docx", "utf-8"));
            String destFileName = planDesignInstance.getName() + "-" + BinaryUtils.getNumberDateTime() + ".docx";
            File destFile = new File("D:\\ztext", destFileName);
            out = new FileOutputStream(new File(destFile.getCanonicalPath()));
            document.write(out);
            return "1";*/

            Long dateTimeFolder = ESUtil.getNumberDate();
            File destFolder = new File(localPath+"/"+dateTimeFolder);
            if(!destFolder.exists()){
                destFolder.mkdirs();
            }
            String destFileName = planDesignInstance.getName() + "-" + BinaryUtils.getNumberDateTime() + ".docx";
            File destFile = new File(destFolder, destFileName);
            out = new FileOutputStream(new File(destFile.getCanonicalPath()));
            document.write(out);
            rsmUtils.uploadRsmFromFile(destFile);
            return httpPath + "/" +dateTimeFolder + "/" + destFileName;
        } catch (Exception e) {
            log.info("导出方案失败!" + e);
            throw new BusinessException("导出方案失败!");
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                throw new BusinessException("关闭流错误!");
            }
        }
    }

    @Override
    public String exportPlan2(HttpServletResponse response, ExportPlanVo exportPlanVo) {
        // 方案数据
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(exportPlanVo.getPlanId());
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案错误!");
        }
        Map<String, String> diagramImageMap = base64ToImagePath(exportPlanVo.getDiagramIcons());
        XWPFDocument document = this.getWord(planDesignInstance, diagramImageMap);
        OutputStream out = null;
        try {
           /* response.setHeader(HttpHeaders.PRAGMA, "No-cache");
            response.setHeader(HttpHeaders.CACHE_CONTROL, "No-cache");
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8");
            //配置导出的word名称&后缀
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(planDesignInstance.getName() + ".docx", "utf-8"));
            String destFileName = planDesignInstance.getName() + "-" + BinaryUtils.getNumberDateTime() + ".docx";
            File destFile = new File("D:\\ztext", destFileName);
            out = new FileOutputStream(new File(destFile.getCanonicalPath()));
            document.write(out);
            return "1";*/

            Long dateTimeFolder = ESUtil.getNumberDate();
            File destFolder = new File(localPath+"/"+dateTimeFolder);
            if(!destFolder.exists()){
                destFolder.mkdirs();
            }
            String destFileName = planDesignInstance.getName() + "-" + BinaryUtils.getNumberDateTime() + ".docx";
            File destFile = new File(destFolder, destFileName);
            out = new FileOutputStream(new File(destFile.getCanonicalPath()));
            document.write(out);
            rsmUtils.uploadRsmFromFile(destFile);
            return httpPath + "/" +dateTimeFolder + "/" + destFileName;
        } catch (Exception e) {
            log.info("导出方案失败!" + e);
            throw new BusinessException("导出方案失败!");
        } finally {
            try {
                if (document != null) {
                    document.close();
                }
                if (out != null) {
                    out.close();
                }
                //删除导出临时生成的图片文件
                if (diagramImageMap != null && !diagramImageMap.isEmpty()) {
                    for (Map.Entry<String, String> entry : diagramImageMap.entrySet()) {
                        String path = entry.getValue();
                        try {
                            FileUtil.delFileOrDir(path);
                        } catch (Exception e) {
                            log.warn("删除文件：{} 错误！", e.getMessage());
                        }
                    }
                }
            } catch (IOException e) {
                throw new BusinessException("关闭流错误!");
            }
        }
    }

    private XWPFDocument getWord(PlanDesignInstance planDesignInstance, Map<String, String> diagramImageMap) {
        XWPFDocument document= new XWPFDocument();
        try {
            // 方案章节数据
            List<PlanChapterVO> chapterList = planChapterInstanceService.getChapterList(planDesignInstance.getId());
            //添加word方案标题
            XWPFParagraph titleParagraph = document.createParagraph();
            //设置段落居中
            titleParagraph.setAlignment(ParagraphAlignment.CENTER);
            XWPFRun titleParagraphRun = titleParagraph.createRun();
            titleParagraphRun.setText(planDesignInstance.getName());
            titleParagraphRun.setColor("000000");
            titleParagraphRun.setFontSize(22);

            // 导出方案章节
            extendPlanChapter(document, chapterList, diagramImageMap);

            return document;
        } catch (BusinessException e) {
            log.info(e.getMessage() + e);
            throw new BusinessException(e.getMessage());
        } catch (Exception e) {
            log.info("导出方案错误!" + e);
            throw new BusinessException("导出方案错误!");
        }
    }

    private void extendPlanChapter(XWPFDocument document, List<PlanChapterVO> chapterList, Map<String, String> diagramImageMap) {
        try {
            for (PlanChapterVO planChapterVO : chapterList) {
                XWPFParagraph firstParagraph = document.createParagraph();
                XWPFRun run = firstParagraph.createRun();
                run.setText(planChapterVO.getSerialNum() + planChapterVO.getName());
                run.setFontFamily("微软雅黑");
                //run.setColor("698869");
                run.setFontSize(13);
                run.setBold(true);
                CTShd cTShd = run.getCTR().addNewRPr().addNewShd();
                cTShd.setVal(STShd.CLEAR);
                //cTShd.setFill("97FF45");
                firstParagraph.setStyle("标题 " + planChapterVO.getLevel());
                addCustomHeadingStyle(document, "标题 " + planChapterVO.getLevel(), planChapterVO.getLevel());
                //run.addTab();

                // 章节内容
                ChapterContext chapterContext = chapterContextDao.getById(planChapterVO.getId());
                List<ContextModule> moduleList = chapterContext.getModuleList();
                if (!CollectionUtils.isEmpty(moduleList)) {
                    for (ContextModule context : moduleList) {
                        PlanTemplateChapterData moduleDefinition = context.getModuleDefinition();
                        Integer type = moduleDefinition.getType();
                        if (Objects.equals(ChapterDataTypeEnum.RICH_TEXT.getDataType(), type)) {
                            // 富文本标题
                            if (moduleDefinition.getNameOnlyEditDisplay() == null || !moduleDefinition.getNameOnlyEditDisplay()) {
                                XWPFParagraph richTextParagraph = document.createParagraph();
                                XWPFRun richTextContext = richTextParagraph.createRun();
                                richTextContext.setText(moduleDefinition.getRichTextName());
                                richTextContext.setFontFamily("微软雅黑");
                                richTextContext.setBold(true);
                                richTextContext.setFontSize(10);
                            }

                            // 富文本内容
                            JSONObject jsonObject = JSONObject.parseObject(context.getData());
                            String data = jsonObject.getString("data");
                            if (!StringUtils.isEmpty(jsonObject.getString("data"))) {
                               /* String[] split = data.split("\n");
                                if (split != null && split.length > 0) {
                                    for (String content : split) {
                                        XWPFParagraph richTextP = document.createParagraph();
                                        // 对其方式
                                        richTextP.setAlignment(ParagraphAlignment.BOTH);
                                        // 段落间距。默认为1行。单位 磅
                                        richTextP.setSpacingBetween(30, LineSpacingRule.EXACT);
                                        // 首行缩进。数值的单位待调整。500大概为缩进2个字符。
                                        richTextP.setIndentationFirstLine(500);
                                        XWPFRun richTextInfo = richTextP.createRun();
                                        richTextInfo.setText(clearHtml(content));
                                        richTextInfo.setFontFamily("微软雅黑");
                                        richTextInfo.setFontSize(10);
                                    }
                                }*/
                                handleText(document,data);
                            }
                        } else if (Objects.equals(ChapterDataTypeEnum.PRODUCT.getDataType(), type)) {
                            // 制品标题
                            if (moduleDefinition.getNameOnlyEditDisplay() == null || !moduleDefinition.getNameOnlyEditDisplay()) {
                                XWPFParagraph productParagraph = document.createParagraph();
                                XWPFRun productContext = productParagraph.createRun();
                                productContext.setText(moduleDefinition.getProductName());
                                productContext.setFontFamily("微软雅黑");
                                productContext.setBold(true);
                                productContext.setFontSize(10);
                                productContext.setText("\r");
                            }

                            JSONObject jsonObject = JSONObject.parseObject(context.getData());
                            if (jsonObject != null && !StringUtils.isEmpty(jsonObject.getString("diagramId"))) {
                                String diagramIdStr = jsonObject.getString("diagramId");
                                String releaseVersionStr = jsonObject.getString("releaseVersion");
                                String diagramKey = diagramIdStr + "_" + releaseVersionStr;
                                String icon1 = null;
                                if (diagramImageMap != null && diagramImageMap.get(diagramKey) != null) {
                                    icon1 = diagramImageMap.get(diagramKey);
                                    if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                        icon1 = httpResouceUrl + icon1;
                                    }
                                    log.info("》》》》》》》》导出使用前端新生成的图片");
                                } else {
                                    Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(jsonObject.getString("diagramId"));
                                    if (diagramId == null) {
                                        continue;
                                    }
                                    log.info("》》》》》》》》导出使用视图原来的缩略图");
                                    ESDiagram diagramInfo = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                    if (diagramInfo != null) {
                                        // 缩略图
                                        icon1 = diagramInfo.getIcon1();
                                        if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                            icon1 = httpResouceUrl + icon1;
                                            diagramInfo.setIcon1(icon1);
                                        }
                                    }
                                }

                                if (icon1 != null) {
                                    // 读取图片
                                    URL url = new URL(icon1);
                                    URLConnection urlConnection = url.openConnection();
                                    InputStream inputStream = urlConnection.getInputStream();
                                    BufferedImage image = ImageIO.read(inputStream);
                                    if (image == null) {
                                        continue;
                                    }

                                    String suffix = icon1.substring(icon1.lastIndexOf(".") + 1, icon1.length());
                                    int picType = Document.PICTURE_TYPE_PNG;
                                    if (Objects.equals(suffix, "png")) {
                                        picType = Document.PICTURE_TYPE_PNG;
                                    } else if (Objects.equals(suffix, "jpg") || Objects.equals(suffix, "jpeg")) {
                                        picType = Document.PICTURE_TYPE_JPEG;
                                    } else if (Objects.equals(suffix, "gif")) {
                                        picType = Document.PICTURE_TYPE_GIF;
                                    }


                                    // 获取图片的原始宽高
                                    int originalWidth = image.getWidth();
                                    int originalHeight = image.getHeight();

                                    // 计算缩放后的宽高，保持比例
                                    double scale = Math.min((double) 330 / originalWidth, (double) 300 / originalHeight);
                                    int scaledWidth = (int) (originalWidth * scale);
                                    int scaledHeight = (int) (originalHeight * scale);

                                    URL url1 = new URL(icon1);
                                    URLConnection urlConnection1 = url1.openConnection();
                                    InputStream inputStream1 = urlConnection1.getInputStream();
                                    XWPFParagraph productP = document.createParagraph();
                                    productP.setAlignment(ParagraphAlignment.CENTER);
                                    XWPFRun productInfo = productP.createRun();
                                    productInfo.addPicture(inputStream1, picType, null, Units.toEMU(scaledWidth), Units.toEMU(scaledHeight));
                                }
                            }
                        } else if (Objects.equals(ChapterDataTypeEnum.DATA_TABLE.getDataType(), type)) {
                            // 导出表格
                            createPlanDataTable(document, moduleDefinition, context, planChapterVO);
                        } else if (Objects.equals(ChapterDataTypeEnum.APPENDIX.getDataType(), type)) {
                            // 表格标题
                            if (moduleDefinition.getNameOnlyEditDisplay() == null || !moduleDefinition.getNameOnlyEditDisplay()) {
                                XWPFParagraph tableParagraph = document.createParagraph();
                                XWPFRun tableContext = tableParagraph.createRun();
                                tableContext.setText(moduleDefinition.getAppendixName());
                                tableContext.setFontFamily("微软雅黑");
                                tableContext.setBold(true);
                                tableContext.setFontSize(10);
                                tableContext.setText("\r");
                            }

                            JSONObject jsonObject = JSONObject.parseObject(context.getData());
                            String data = jsonObject.getString("data");
                            if (!StringUtils.isEmpty(data)) {
                                JSONArray jsonArray = JSONObject.parseArray(data);
                                if (!CollectionUtils.isEmpty(jsonArray)) {
                                    for (int i = 0; i < jsonArray.size(); i++) {
                                        JSONObject jsonData = JSONObject.parseObject(String.valueOf(jsonArray.get(i)));
                                        // 添加超链接
                                        XWPFParagraph p1 = document.createParagraph();
                                        p1.setIndentationFirstLine(500);
                                        String resourcePath = jsonData.getString("resourcePath");
                                        resourcePath = resourcePath.replace("/rsm", "");
                                        resourcePath = resourcePath.replace("rsm", "");
                                        XWPFHyperlinkRun hyperlink = p1.createHyperlinkRun(httpPath + resourcePath);
                                        hyperlink.setUnderline(UnderlinePatterns.SINGLE);
                                        hyperlink.setColor("0000ff");
                                        hyperlink.setText(jsonData.getString("name"));
                                    }
                                }
                            }
                        } else if (Objects.equals(ChapterDataTypeEnum.DATA_SET.getDataType(), type)) {
                            // 清单制品标题
                            if (moduleDefinition.getNameOnlyEditDisplay() == null || !moduleDefinition.getNameOnlyEditDisplay()) {
                                XWPFParagraph tableParagraph = document.createParagraph();
                                XWPFRun tableContext = tableParagraph.createRun();
                                tableContext.setText(moduleDefinition.getDataSetName());
                                tableContext.setFontFamily("微软雅黑");
                                tableContext.setBold(true);
                                tableContext.setFontSize(10);
                            }

                            JSONObject dataSet = dataSetApiSvc.findDataSetById(moduleDefinition.getDataSetId());
//                            XWPFParagraph dataSetP = document.createParagraph();
//                            dataSetP.setIndentationFirstLine(500);
//                            XWPFRun dataSetType = dataSetP.createRun();
//                            dataSetType.setText("清单类型" + "     " + dataSet.getString("name"));
//                            dataSetType.setFontFamily("微软雅黑");
//                            dataSetType.setFontSize(10);

                            // 通过数据集获取数据
                            Integer limit = 100;
                            SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
                            dataSet.put("domainId", currentUserInfo.getDomainId());
                            List<DataSetExeResultSheetPage> resultUsingRuleList = dataSetApiSvc.getResultUsingRule(dataSet, limit);
                            if (!CollectionUtils.isEmpty(resultUsingRuleList)) {
                                for (DataSetExeResultSheetPage dataSetResult : resultUsingRuleList) {
//                                    List<String> pathList = dataSetResult.getPath();
//                                    String join = String.join(" —> ", pathList);
//                                    XWPFParagraph dataSetPara = document.createParagraph();
//                                    dataSetPara.setIndentationFirstLine(500);
//                                    XWPFRun dataSetPath = dataSetPara.createRun();
//                                    dataSetPath.setText("路径" + "     " + join);
//                                    dataSetPath.setFontFamily("微软雅黑");
//                                    dataSetPath.setFontSize(10);

                                    List<String> tableHeadList = new ArrayList<>();
                                    List<Map<String, String>> headers = dataSetResult.getHeaders();
                                    for (Map<String, String> headerData : headers) {
                                        tableHeadList.add(headerData.get("attrName"));
                                    }

                                    //创建表格
                                    XWPFTable ComTable = document.createTable();
                                    ComTable.setWidth("100%");
                                    //列宽自动分割
                                    /*CTTblWidth comTableWidth = ComTable.getCTTbl().addNewTblPr().addNewTblW();
                                    comTableWidth.setType(STTblWidth.DXA);
                                    comTableWidth.setW(BigInteger.valueOf(7000));*/

                                    // 表格缩进
                                    CTTblWidth tblInd = ComTable.getCTTbl().getTblPr().getTblInd();
                                    if (null == tblInd) {
                                        tblInd = ComTable.getCTTbl().getTblPr().addNewTblInd();
                                    }
                                    //缩进距离
                                    tblInd.setW(BigInteger.valueOf(0));
                                    ComTable.getCTTbl().getTblPr().setTblInd(tblInd);

                                    //表头
                                    XWPFTableRow comTableRowOne = ComTable.getRow(0);
                                    String width = BigDecimal.ONE.divide(new BigDecimal(tableHeadList.size()), 2, BigDecimal.ROUND_HALF_UP)
                                            .multiply(new BigDecimal("100")).setScale(0).toString() + "%";
                                    for (int i = 0; i < tableHeadList.size(); i++) {
                                        if (i == 0) {
                                            XWPFTableCell cell = comTableRowOne.getCell(0);
                                            if (Objects.equals(tableHeadList.size(), 2)) {
                                                cell.setWidth("20%");
                                            } else {
                                                cell.setWidth(width);
                                            }
                                            cell.setText(tableHeadList.get(i));
                                        } else {
                                            XWPFTableCell cell = comTableRowOne.addNewTableCell();
                                            if (Objects.equals(tableHeadList.size(), 2)) {
                                                cell.setWidth("80%");
                                            } else {
                                                cell.setWidth(width);
                                            }
                                            cell.setText(tableHeadList.get(i));
                                        }
                                        // 设置水平居中
                                        XWPFTableCell cell = comTableRowOne.getTableCells().get(i);
                                        CTTc cttc = cell.getCTTc();
                                        CTTcPr ctPr = cttc.addNewTcPr();
                                        ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
                                        cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
                                        cell.setColor("D9D9D9");
                                    }

                                    List<Map<String, Object>> dataList = dataSetResult.getData();
                                    for (int i = 0; i < dataList.size(); i++) {
                                        Map<String, Object> dataMap = dataList.get(i);
                                        XWPFTableRow comTableRowTwo = ComTable.createRow();
                                        for (int j = 0; j < headers.size(); j++) {
                                            String cellWidth = null;
                                            if (Objects.equals(headers.size(), 2)) {
                                                if (Objects.equals(j, 0)) {
                                                    cellWidth = "20%";
                                                } else {
                                                    cellWidth = "80%";
                                                }
                                            } else {
                                                cellWidth = width;
                                            }

                                            Map<String, String> headerMap = headers.get(j);
                                            String attrKey = headerMap.get("attrKey");
                                            Object dataObj = dataMap.get(attrKey);
                                            if (dataObj != null) {
                                                String data = String.valueOf(dataObj);
                                                XWPFTableCell cell = comTableRowTwo.getCell(j);
                                                cell.setWidth(cellWidth);
                                                cell.setText(data);
                                            }

                                            // 设置水平居中
                                            XWPFTableCell cell = comTableRowTwo.getTableCells().get(j);
                                            CTTc cttc = cell.getCTTc();
                                            CTTcPr ctPr = cttc.addNewTcPr();
                                            ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
                                            //cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (!CollectionUtils.isEmpty(planChapterVO.getChildChapterList())) {
                    extendPlanChapter(document, planChapterVO.getChildChapterList(), diagramImageMap);
                }
            }
        } catch (Exception e) {
            log.info("方案章节导出word错误!" + e);
            throw new BusinessException("方案章节导出word错误!");
        }
    }

    private void handleTableBindAsset(RowTableContentVo dataTableContent, Long planId, String value, int j, XWPFTableRow comTableRowTwo, String cellWidth) {
        if (StringUtils.isNotBlank(value) || planId == null) {
            XWPFTableCell cell = comTableRowTwo.getCell(j);
            cell.setWidth(cellWidth);
            cell.setText("");
            return;
        }
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
        if (planDesignInstance == null) {
            XWPFTableCell cell = comTableRowTwo.getCell(j);
            cell.setWidth(cellWidth);
            cell.setText("");
            return;
        }
        // 系统分类
        Long classId = planDesignInstance.getDefaultSystemClassId();
        if (classId == null) {
            XWPFTableCell cell = comTableRowTwo.getCell(j);
            cell.setWidth(cellWidth);
            cell.setText("");
            return;
        }
        List<ESCIAttrDefInfo> attrDefList = new ArrayList<>();
        ESCIClassInfo esciClassInfo = ciClassSvc.queryESClassInfoById(classId);
        if (esciClassInfo != null && !CollectionUtils.isEmpty(esciClassInfo.getAttrDefs())) {
            attrDefList = esciClassInfo.getAttrDefs();
        }
        if (CollectionUtils.isEmpty(attrDefList)) {
            XWPFTableCell cell = comTableRowTwo.getCell(j);
            cell.setWidth(cellWidth);
            cell.setText("");
            return;
        }
        Map<Long, String> attrMap = attrDefList.stream().collect(Collectors.toMap(ESCIAttrDefInfo::getId, ESCIAttrDefInfo::getProName));
        String val = "";
        if (!StringUtils.isEmpty(dataTableContent.getCopyConstraint())) {
            Long attId = null;
            String item = dataTableContent.getCopyConstraint();
            JSONObject jsonObject = JSONObject.parseObject(item);
            if (jsonObject != null && !StringUtils.isEmpty(jsonObject.getString("ids"))
                    && attrMap.containsKey(Long.valueOf(jsonObject.getString("ids")))) {
                attId = Long.valueOf(jsonObject.getString("ids"));
            }
            if (attId != null) {
                String preName = attrMap.get(attId);

                CcCiInfo ci = null;
                ESCISearchBean bean = new ESCISearchBean();
                CCcCi cdt = new CCcCi();
                cdt.setCiCode(planDesignInstance.getDefaultSystemCiCode());
                bean.setCdt(cdt);
                CiGroupPage ciGroupPage = ciSwitchSvc.queryPageBySearchBean(bean, false, LibType.DESIGN);
                if (ciGroupPage != null && !CollectionUtils.isEmpty(ciGroupPage.getData())) {
                    ci = ciGroupPage.getData().get(0);
                }

                if (ci != null) {
                    Map<String, String> attrs = ci.getAttrs();
                    val = attrs.get(preName);
                }
            }
        }
        XWPFTableCell cell = comTableRowTwo.getCell(j);
        cell.setWidth(cellWidth);
        cell.setText(val);
    }

    private void handleText(XWPFDocument document, String htmlContent) {
        // 解析 HTML 内容
        org.jsoup.nodes.Document doc = Jsoup.parse(htmlContent);
        Elements elements = doc.body().children();// 获取所有顶层的HTML元素
        for (Element element : elements) {
            //处理不同的标签类型
            switch (element.tagName()) {
                case "p" :
                    processParagraph(element,document);
                    break;
                case "img" :
                    processImage(element,document,null,0,0);
                    break;
                case "table":
                    processTable(element,document);
                    break;
                default:
                    processParagraph(element,document);//其他类型暂时先把它当做文本处理
                    break;
            }

        }
    }
    /**
     *  生成方案内表格数据
     * @param document
     * @param moduleDefinition
     * @param context
     * @param planChapterVO
     */
    private void createPlanDataTable(XWPFDocument document, PlanTemplateChapterData moduleDefinition,
                                     ContextModule context, PlanChapterVO planChapterVO) {
        if (moduleDefinition.getNameOnlyEditDisplay() == null || !moduleDefinition.getNameOnlyEditDisplay()) {
            XWPFParagraph tableParagraph = document.createParagraph();
            XWPFRun tableContext = tableParagraph.createRun();
            tableContext.setText(moduleDefinition.getDataTableName());
            tableContext.setFontFamily("微软雅黑");
            tableContext.setBold(true);
            tableContext.setFontSize(10);
            tableContext.setText("\r");
        }
        //创建表格
        XWPFTable ComTable = document.createTable();
        //列宽自动分割
        CTTblWidth comTableWidth = ComTable.getCTTbl().addNewTblPr().addNewTblW();
        comTableWidth.setType(STTblWidth.DXA);
        comTableWidth.setW(BigInteger.valueOf(7000));
        // 表格缩进
        CTTblWidth tblInd = ComTable.getCTTbl().getTblPr().getTblInd();
        if (null == tblInd) {
            tblInd = ComTable.getCTTbl().getTblPr().addNewTblInd();
        }
        //缩进距离
        tblInd.setW(BigInteger.valueOf(500));
        ComTable.getCTTbl().getTblPr().setTblInd(tblInd);
        //表头
        XWPFTableRow comTableRowOne = ComTable.getRow(0);
        PlanTemplateChapterData definition = context.getModuleDefinition();

        if (Objects.equals(definition.getDataTableForm(), 1)) {
            // 横向表格
            createTableService.getHorizontalTable(definition, comTableRowOne, context, ComTable, planChapterVO);
        } else if (Objects.equals(definition.getDataTableForm(), 2)) {
            // 纵向表格
            createTableService.getVerticalTable(definition, comTableRowOne, context, ComTable);
        } else if (Objects.equals(definition.getDataTableForm(), 3)) {
            // 矩阵表格行
            createTableService.getMatrixTable(definition, comTableRowOne, context, ComTable);
        }
    }


    private void processParagraph(Element paragraph, XWPFDocument document) {
        Elements images = paragraph.getElementsByTag("img");
        if (!images.isEmpty()) {
            for (Element image : images) {
                String src = image.attr("src");
                int width = parsePixeValue(image.attr("width"));
                int height = parsePixeValue(image.attr("height"));
                processImage(null,document,src,width,height);
            }
        }else {
            XWPFParagraph p = document.createParagraph();
            XWPFRun run = p.createRun();
            run.setText(paragraph.text());
        }
    }

    private int parsePixeValue(String value) {
        try {
            return Integer.parseInt(value.replace("px", ""));
        } catch (Exception e) {
            return 0 ;
        }
    }

    private double getTableWidth(Element tableElement, long totalTableWidthTwips) {
        String style = tableElement.attr("style");
        String widthStyle = style.replaceAll(".*width: (.*?);.*", "$1").trim();
        if (widthStyle.endsWith("%")) {
            double widthPercentage = Double.parseDouble(widthStyle.replace("%",""));
            return (double)totalTableWidthTwips * (widthPercentage / 100.0);
        }else {
            return 0.0;
        }
    }

    private void processImage(Element element, XWPFDocument document,String imageUrl,int width,int height) {
        try {
            if (!BinaryUtils.isEmpty(element) && BinaryUtils.isEmpty(imageUrl)) {
                imageUrl = element.attr("src");
            }
            if (imageUrl != null) {
                int picType = determinePictureFormat(imageUrl);
                // 读取图片
                URL url = new URL(imageUrl);
                URLConnection urlConnection = url.openConnection();
                InputStream inputStream = urlConnection.getInputStream();
                BufferedImage image = ImageIO.read(inputStream);
                if (image == null) {
                    return;
                }
                // 获取图片的原始宽高
                int originalWidth = image.getWidth();
                int originalHeight = image.getHeight();

                // 计算缩放后的宽高，保持比例
                double scale = Math.min((double) 330 / originalWidth, (double) 300 / originalHeight);
                int scaledWidth = (int) (originalWidth * scale);
                int scaledHeight = (int) (originalHeight * scale);

                URL url1 = new URL(imageUrl);
                URLConnection urlConnection1 = url1.openConnection();
                InputStream inputStream1 = urlConnection1.getInputStream();
                XWPFParagraph productP = document.createParagraph();
                productP.setAlignment(ParagraphAlignment.CENTER);
                XWPFRun productInfo = productP.createRun();
                productInfo.addPicture(inputStream1, picType, null, Units.toEMU(scaledWidth), Units.toEMU(scaledHeight));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void processTable(Element tableElement, XWPFDocument document) {
        Elements rows = tableElement.select("tr");
        XWPFTable table = document.createTable(rows.size(),rows.first().select("td").size());
        //给定表格初始化页面宽度，因为前端是自适应的百分比取值
        long totalTableWidthTwips = 30000L;
        double tableWidth = getTableWidth(tableElement,totalTableWidthTwips);
        for (int i = 0; i < rows.size(); i++) {
            Element row = rows.get(i);
            Elements cells = row.select("td");
            String rowHeightStyle = row.attr("style").replaceAll(".*height: (.*?);.*", "$1").trim().replace("px", "");
            long rowHeightValue;
            if (!rowHeightStyle.isEmpty()) {
                rowHeightValue = (long)(Double.parseDouble(rowHeightStyle) * 0.75 * 20.0);
                table.getRow(i).setHeight((int) rowHeightValue);
            }else {
                rowHeightValue = 750L;
                table.getRow(i).setHeight((int)rowHeightValue);
            }
            for (int j = 0; j < cells.size(); j++) {
                Element cell = cells.get(j);
                String cellText = cell.text();
                XWPFTableCell tableCell = table.getRow(i).getCell(j);
                tableCell.setText(cellText);
                String cellWidthStyle = cell.attr("style").replaceAll(".*width: (.*?);.*", "$1").trim();
                if (!cellWidthStyle.isEmpty() && cellWidthStyle.endsWith("%")) {
                    double cellWidthPercentage = Double.parseDouble(cellWidthStyle.replace("%",""));
                    long cellWidthValue = (long)(cellWidthPercentage / 100.0 * tableWidth);
                    if (tableCell.getCTTc() != null && tableCell.getCTTc().getTcPr() == null) {
                        tableCell.getCTTc().addNewTcPr();
                    }
                    if (tableCell.getCTTc() != null && tableCell.getCTTc().getTcPr() != null) {
                        tableCell.getCTTc().getTcPr().addNewTcW().setW(BigInteger.valueOf(cellWidthValue));
                    }
                }
            }
        }

    }

    /**
     * base64保存为本地图片 返回url
     * @param base64Map
     * @return
     */
    private Map<String, String> base64ToImagePath(Map<String, String> base64Map) {
        if (base64Map == null || base64Map.isEmpty()) {
            return null;
        }
        Map<String, String> imagePathMap = new HashMap<>();
        // 遍历原始Map并进行转换
        for (Map.Entry<String, String> entry : base64Map.entrySet()) {
            String id = entry.getKey();
            String base64Image = entry.getValue();
            try {
                String path = saveOrUpdateThumbnail(base64Image);
                imagePathMap.put(id, path);
            } catch (Exception e) {
                log.error("无法转换ID为 " + id + " 的图像: " + e.getMessage());
            }
        }
        return imagePathMap;
    }

    private String saveOrUpdateThumbnail(String base64) {
        String iconPath = new StringBuilder(UUID.randomUUID().toString()).append(".png").toString();
        try {
            iconPath = this.saveOrUpdatePng(iconPath, base64, true);
        } catch (Exception e) {
            log.error("保存缩略图异常", e.getMessage());
        }
        return iconPath;
    }

    private String saveOrUpdatePng(String filePath, String fileContent, boolean create) {
        byte[] bs;
        if (fileContent.length() >= fileContent.indexOf(";base64,") + 8) {
            String substring = fileContent.substring(fileContent.indexOf(";base64,") + 8);
            bs = org.apache.commons.codec.binary.Base64.decodeBase64(substring);

            filePath = this.saveOrUpdateResource(filePath, bs, create);

        }
        return filePath;
    }

    /**
     * 将字符串保存/更新 为文件，自动加上日期前缀
     *
     * @param filePath    文件名或文件相对路径
     * @param fileContent 文件内容
     * @return 文件名或文件相对路径
     * @throws IOException
     */
    public String saveOrUpdateResource(String filePath, byte[] fileContent, boolean create) {
        if (create) {
            filePath = Paths.get("/" + LocalDate.now(), filePath).toString();
        }
        try {
            FileUtil.writeFile(filePath, fileContent);
        } catch (IOException e) {
            log.warn("写入文件：{} 错误！", filePath, e);
        }
        return filePath;
    }

    //判断图片类型
    private int determinePictureFormat(String imgSrc) {
        String fileExtension = imgSrc.substring(imgSrc.lastIndexOf(".")+1).toLowerCase();
        switch (fileExtension) {
            case "jpeg":
            case "jpg":
                return XWPFDocument.PICTURE_TYPE_JPEG;
            case "png":
                return XWPFDocument.PICTURE_TYPE_PNG;
            case "gif":
                return XWPFDocument.PICTURE_TYPE_GIF;
            case "bmp":
                return XWPFDocument.PICTURE_TYPE_BMP;
            case "tiff":
                return XWPFDocument.PICTURE_TYPE_TIFF;
            case "emf":
                return XWPFDocument.PICTURE_TYPE_EMF;
            case "wmf":
                return XWPFDocument.PICTURE_TYPE_WMF;
            default:
                return -1; //未知格式

        }
    }

    private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
        CTStyle ctStyle = CTStyle.Factory.newInstance();
        ctStyle.setStyleId(strStyleId);
        CTString styleName = CTString.Factory.newInstance();
        styleName.setVal(strStyleId);
        ctStyle.setName(styleName);
        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
        indentNumber.setVal(BigInteger.valueOf(headingLevel));
        // lower number > style is more prominent in the formats bar
        ctStyle.setUiPriority(indentNumber);

        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
        ctStyle.setUnhideWhenUsed(onoffnull);
        // style shows up in the formats bar
        ctStyle.setQFormat(onoffnull);
        // style defines a heading of the given level
        CTPPr ppr = CTPPr.Factory.newInstance();
        ppr.setOutlineLvl(indentNumber);
        ctStyle.setPPr(ppr);
        XWPFStyle style = new XWPFStyle(ctStyle);
        // is a null op if already defined
        XWPFStyles styles = docxDocument.createStyles();
        style.setType(STStyleType.PARAGRAPH);
        styles.addStyle(style);
    }

    private String clearHtml(String htmlStr) {
        //定义script的正则表达式，去除js可以防止注入
        String scriptRegex = "<script[^>]*?>[\\s\\S]*?<\\/script>";
        //定义style的正则表达式，去除style样式，防止css代码过多时只截取到css样式代码
        String styleRegex = "<style[^>]*?>[\\s\\S]*?<\\/style>";
        //定义HTML标签的正则表达式，去除标签，只提取文字内容
        String htmlRegex = "<[^>]+>";
        //定义空格,回车,换行符,制表符
        String spaceRegex = "\\s*|\t|\r|\n";
        // 过滤script标签
        htmlStr = htmlStr.replaceAll(scriptRegex, "");
        // 过滤style标签
        htmlStr = htmlStr.replaceAll(styleRegex, "");
        // 过滤html标签
        htmlStr = htmlStr.replaceAll(htmlRegex, "");
        // 过滤空格等
        htmlStr = htmlStr.replaceAll(spaceRegex, "");
        // 过滤&nbsp;
        htmlStr = htmlStr.replace("&nbsp;", "");
        // 过滤&nbsp
        htmlStr = htmlStr.replace("&nbsp", "");
        // 返回文本字符串
        htmlStr = htmlStr.trim();
        //去除空格" "
        htmlStr = htmlStr.replaceAll(" ", "");
        return htmlStr;
    }

    @Override
    public List<PlanDesignInstance> findPlanInstanceList(List<MinePlanQueryVo> minePlanQueryVos) {
        if (CollectionUtils.isEmpty(minePlanQueryVos)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        for (MinePlanQueryVo planQueryVo : minePlanQueryVos) {
            BoolQueryBuilder childQuery = QueryBuilders.boolQuery();
            childQuery.must(QueryBuilders.termQuery("businessKey.keyword", planQueryVo.getBusinessKey()));
            childQuery.must(QueryBuilders.termsQuery("status.keyword", planQueryVo.getStatusList()));
            query.should(childQuery);
        }
        return planDesignInstanceDao.getSortListByQuery(1, 3000, query, "createTime", false).getData();
    }

    @Override
    public Boolean batchDeletePublishedPlan(List<Long> planIds) {
        BoolQueryBuilder planQuery = QueryBuilders.boolQuery();
        planQuery.must(QueryBuilders.termsQuery("id", planIds));
        List<PlanDesignInstance> planDesignList = planDesignInstanceDao.getListByQuery(planQuery);
        if (CollectionUtils.isEmpty(planDesignList)) {
            return true;
        }
        Set<String> businessKeySet = planDesignList.stream().map(planDesignInstance -> planDesignInstance.getBusinessKey()).collect(Collectors.toSet());

        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("businessKey.keyword", businessKeySet));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        query.must(QueryBuilders.termsQuery("status.keyword", Lists.newArrayList(PlanStatusEnum.published.name(), PlanStatusEnum.history.name())));
        List<PlanDesignInstance> planDesignInstanceList = planDesignInstanceDao.getListByQuery(query);
        if (!CollectionUtils.isEmpty(planDesignInstanceList)) {
            List<Long> publishPlanId = planDesignInstanceList.stream().map(PlanDesignInstance::getId).collect(Collectors.toList());

            //删除方案和资产文件夹关系数据
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termsQuery("planId", publishPlanId));
            dirRelationPlanDao.deleteByQuery(queryBuilder, true);

            // 删除方案关联制品
            planArtifactService.deletePlanArtifactByPlanIds(publishPlanId);

            // 删除资产库发布的和历史版本方案
            planDesignInstanceDao.deleteByIds(publishPlanId);
        }
        // TODO 工作台戴珊消息
        //systemDiagramFeign.deletePublishMessage(planDesignInstanceList.getBusinessKey());

        // 修改设计库的状态
        BoolQueryBuilder designQuery = QueryBuilders.boolQuery();
        designQuery.must(QueryBuilders.termsQuery("businessKey.keyword", businessKeySet));
        designQuery.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        List<PlanDesignInstance> designPlanList = planDesignInstanceDao.getListByQuery(designQuery);
        if (!CollectionUtils.isEmpty(designPlanList)) {
            designPlanList.forEach(plan -> {
                plan.setModifyTime(ESUtil.getNumberDateTime());
                if (Objects.equals(plan.getStatus(), PlanStatusEnum.published.name())) {
                    plan.setStatus(PlanStatusEnum.draft.name());
                } else if (Objects.equals(plan.getStatus(), PlanStatusEnum.deleted.name())) {
                    plan.setDeleteBeforeStatus(PlanStatusEnum.draft.name());
                }
            });
            planDesignInstanceDao.saveOrUpdateBatch(designPlanList);
        }
        //删除方案的时候删除我的最近查看和我的关注关联表数据
        CEamAttention eamAttention = new CEamAttention();
        eamAttention.setAttentionIds(planIds);
        eamAttention.setAttentionType(3);
        if (planDesignList.get(0).getDirType() == 11) {
            eamAttention.setAttentionBuild(3);
        }

        if (planDesignList.get(0).getDirType() == 1) {
            eamAttention.setAttentionBuild(1);
        }
        if (planDesignList.get(0).getDirType() == 110) {
            eamAttention.setAttentionBuild(6);
        }
        attentionSvc.batchCancelAttention(eamAttention);
        CEamRecentlyView eamRecentlyView = new CEamRecentlyView();
        eamRecentlyView.setPlanIds(planIds);
        recentlyViewSvc.batchCancelRecentlyView(eamRecentlyView);
        return true;
    }

    @Override
    public List<PlanDesignInstance> findPlanInstanceListByDirId(Long dirId, List<Long> assetsDirIds) {
        if (dirId == null && CollectionUtils.isEmpty(assetsDirIds)) {
            throw new BusinessException("参数不能为空!");
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if (dirId != null) {
            query.must(QueryBuilders.termQuery("dirId", dirId));
        }
        if (!CollectionUtils.isEmpty(assetsDirIds)) {
            query.must(QueryBuilders.termsQuery("assetsDirId", assetsDirIds));
        }
        return planDesignInstanceDao.getListByQuery(query);
    }

    @Override
    public void updatePlanBatch(List<PlanDesignInstance> planDesignInstanceList) {
        if (CollectionUtils.isEmpty(planDesignInstanceList)) {
            return;
        }
        planDesignInstanceDao.saveOrUpdateBatch(planDesignInstanceList);
    }

    @Override
    public Page<PlanDesignInstanceDTO> getSystemPlan(Integer pageNum, Integer pageSize, String ciCode) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
        query.must(QueryBuilders.termQuery("defaultSystemCiCode.keyword", ciCode));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
        Page<PlanDesignInstance> page = planDesignInstanceDao.getSortListByQuery(pageNum, pageSize, query, "modifyTime", false);
        List<PlanDesignInstanceDTO> instanceDTOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(page.getData())) {
            for (PlanDesignInstance instance : page.getData()) {
                PlanDesignInstanceDTO instanceDTO = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(instance, instanceDTO);
                instanceDTOS.add(instanceDTO);
            }
        }
        return new Page<>(pageNum, pageSize, page.getTotalRows(), page.getTotalPages(), instanceDTOS);
    }

    @Override
    public Page<PlanDesignInstanceDTO> getSystemPlan(Integer pageNum, Integer pageSize, String ciCode,List<Long> relevanceIds) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
        query.must(QueryBuilders.termQuery("assetsType", Constants.ASSETS));
//        query.must(QueryBuilders.termQuery("defaultSystemCiCode.keyword", ciCode));
        BoolQueryBuilder queryBuilder2 = QueryBuilders.boolQuery();
        query.must(queryBuilder2);
        queryBuilder2.should(QueryBuilders.multiMatchQuery(ciCode,"ciCodeList").operator(Operator.AND).type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX).lenient(true));
        if (!CollectionUtils.isEmpty(relevanceIds)) {
            queryBuilder2.should(QueryBuilders.termsQuery("id", relevanceIds));
        }
        Page<PlanDesignInstance> page = planDesignInstanceDao.getSortListByQuery(pageNum, pageSize, query, "modifyTime", false);
        List<Long> planIds = page.getData().stream().map(planDesignInstance -> planDesignInstance.getId()).collect(Collectors.toList());
        Map<String, List<PlanDesignInstance>> planHistoryVersionListByIds = findPlanHistoryVersionListByIds(planIds);
        List<PlanDesignInstanceDTO> instanceDTOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(page.getData())) {
            for (PlanDesignInstance instance : page.getData()) {
                PlanDesignInstanceDTO instanceDTO = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(instance, instanceDTO);
                List<PlanDesignInstance> planDesignInstances = planHistoryVersionListByIds.get(instance.getBusinessKey());
                Integer version = 1;
                if (!CollectionUtils.isEmpty(planDesignInstances)) {
                    version = planDesignInstances.size();
                }
                instanceDTO.setVersion(version);
                instanceDTOS.add(instanceDTO);
            }
        }
        return new Page<>(pageNum, pageSize, page.getTotalRows(), page.getTotalPages(), instanceDTOS);
    }

    private TaskResponse processApproval(ProcessApprovalRequest request, PlanDesignInstance plan, SysUser user, String processDefinitionKey) {
        String taskId = null;
        // 开启审批
        if (StringUtils.isEmpty(request.getTaskId())) {
            // 先判断是否已开启流程任务
            if (!StringUtils.isEmpty(plan.getTaskId())) {
                taskId = plan.getTaskId();
            } else {
                // 开启功能需求视图子流程
                PorcessResponse porcessResponse = demandProcess(plan, processDefinitionKey, user);
                if (porcessResponse == null) {
                    throw new BusinessException("执行流程审批失败!");
                }
                taskId = porcessResponse.getTaskId();

                // 保存方案提交审批前的状态，终止流程时使用
                if (!plan.isProcessApproval() && StringUtils.isEmpty(plan.getTaskId())) {
                    String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
                    iCacheService.setCache(key, plan.getStatus());
                }
            }
        } else {
            taskId = request.getTaskId();
        }

        // 执行审批
        TaskRequest taskRequest = new TaskRequest();
        taskRequest.setTaskId(taskId);
        taskRequest.setAction(FLOWACTION.ACCETP);
        // 过滤掉已经同意的用户
        taskRequest.setFilterUser(Boolean.TRUE);
        TaskResponse taskResponse = null;
        try {
            taskResponse = flowableFeign.completeTask(taskRequest);
            if (taskResponse != null && taskResponse.getErrorCode() == 60001) {
                throw new BusinessException("请配置审批角色和用户!");
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage());
        } catch (Exception e) {
            if (Objects.equals(processDefinitionKey, FlowableConstant.XW_BUSINESS_SCENARIO_APPROVE)) {
                // eamPlanModelApprovalSvc.cancel(String.valueOf(plan.getId()));
            } else {
                cancelPlan(plan);
            }
            ProcessRequest processRequest = new ProcessRequest();
            processRequest.setBusinessKey(String.valueOf(plan.getId()));
            flowableFeign.deleteProcessInstanceByBusinessId(processRequest);
            // 删除工作台待办已办
            TaskResponse workbenchTask = flowableFeign.getTaskInfoByTaskId(taskId);
            if (workbenchTask != null && !StringUtils.isEmpty(workbenchTask.getProcessInstanceId())) {
                WorkbenchChargeDone workbenchChargeDone = new WorkbenchChargeDone();
                workbenchChargeDone.setProcessInstanceId(workbenchTask.getProcessInstanceId());
                workbenchChargeDoneSvc.deleteByCondition(workbenchChargeDone);
            }
            throw new BusinessException("方案提交审批失败!");
        }
        return taskResponse;
    }

    private PorcessResponse demandProcess(PlanDesignInstance plan, String processDefinitionKey, SysUser user) {
        List<ChildProcessRequest> childProcessRequestList = new ArrayList<>();

        ProcessRequest approveParamRequest = new ProcessRequest();
        Map<String, Object> routeVariables = new HashMap<>();
        routeVariables.put("releaseDirId", plan.getAssetsDirId());
        approveParamRequest.setRouterVariables(routeVariables);
        approveParamRequest.setProcessDefinitionKey(processDefinitionKey);
        approveParamRequest.setBusinessKey(String.valueOf(plan.getId()));
        approveParamRequest.setProcessInstanceName(plan.getName() + Constants.START_APPROVE);
        approveParamRequest.setUserId(user.getLoginCode());
        approveParamRequest.setOwner(user.getLoginCode());
        // 发起功能需求子流程审批
        if (!CollectionUtils.isEmpty(childProcessRequestList)) {
            approveParamRequest.setChildProcessRequestList(childProcessRequestList);
            log.info("########## 子流程参数信息childProcessRequest：【{}】", JSONObject.toJSONString(childProcessRequestList));
        }
        PorcessResponse approveParamResponse = flowableFeign.startProcessBindAssignee(approveParamRequest);
        if (approveParamResponse != null) {
            sendShareSubmitIfNeed(plan);
        }
        log.info("功能需求开启子流程");
        return approveParamResponse;
    }

    private void sendShareSubmitIfNeed(PlanDesignInstance plan) {
        //提交审批人是否当前用户
        String curLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(curLoginCode);
        if (curLoginCode.equals(plan.getCreatorCode())) {
            return;
        }
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        builder.must(QueryBuilders.termQuery("planDesignId", plan.getId()));
        builder.must(QueryBuilders.termQuery("sharedLoginCode.keyword", curLoginCode));
        builder.must(QueryBuilders.termQuery("status", PlanShareEnum.SHARING.getStatus()));
        List<PlanDesignShareRecord> shareRecordList = planDesignShareRecordDao.getListByQuery(builder);
        if (CollectionUtils.isEmpty(shareRecordList)) {
            return;
        }
        PlanDesignShareRecord shareRecord = shareRecordList.get(0);
        //获取当前协作者权限
        if (shareRecord.getPermission() == null || shareRecord.getPermission() != 4) {
            return;
        }
        //给方案创建人发送协作者提交审批消息：您创建的 【视图/方案】 【视图/方案名称】 已由【提交人】提交审批
        SharePublishAssertMsgVo sharePublishAssertMsgVo = new SharePublishAssertMsgVo();
        sharePublishAssertMsgVo.setAssertOwnerCode(plan.getCreatorCode());
        sharePublishAssertMsgVo.setType(NoticeConstant.TAG_PLAN);
        sharePublishAssertMsgVo.setAssertName(plan.getName());
        sharePublishAssertMsgVo.setAssertId(plan.getId().toString());
        sharePublishAssertMsgVo.setShareUserId(userInfo.getId());
        sharePublishAssertMsgVo.setShareUserName(userInfo.getUserName());
        eamNoticeService.sharePublishAssertMsgSave(sharePublishAssertMsgVo);
    }

    @Override
    public void saveOrUpdate(PlanDesignInstance planDesignInstance) {
        planDesignInstanceDao.saveOrUpdate(planDesignInstance);
    }

    @Override
    public void saveOrUpdateBatch(List<PlanDesignInstance> planDesignInstances) {
        planDesignInstanceDao.saveOrUpdateBatch(planDesignInstances);
    }

    private Long publishDiagramAndPlan(PlanDesignInstance plan, UserInfo userInfo, Boolean archReview) {
        EamCategory category = null;
        try {
            category = categorySvc.getById(plan.getAssetsDirId(), LibType.DESIGN);
        } catch (Exception e) {
            // 再流程中的方案发布状态是草稿
            plan.setStatus(PlanStatusEnum.draft.name());
            plan.setProcessApproval(false);
            plan.setTaskId("");
            planDesignInstanceDao.saveOrUpdate(plan);
            // 修改方案中视图状态
            updateDiagramState(plan.getId(), 0);

            log.error("获取方案发布位置错误：", e);
            throw new BusinessException(e.getMessage());
        }
        // 如果位置为空，返回固定的编码，前端作特殊化处理
        if (category == null) {
            // 再流程中的方案发布状态是草稿
            plan.setStatus(PlanStatusEnum.draft.name());
            plan.setProcessApproval(false);
            plan.setTaskId("");
            planDesignInstanceDao.saveOrUpdate(plan);
            // 修改方案中视图状态
            updateDiagramState(plan.getId(), 0);

            return -2L;
        }

        // 处理历史版本方案
        PlanDesignInstance planDesignInstance = handlerHistoryPlan(plan, userInfo);

        try {
            // 发布视图
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            queryBuilder.must(QueryBuilders.termQuery("planId", planDesignInstance.getId()));
            List<ChapterContext> contextList = chapterContextDao.getListByQuery(queryBuilder);
            handlerPublishDiagram(contextList, planDesignInstance);

            // 发布方案,与文件夹创建关联关系，作用不大后期删掉
            handleDirRelationPlan(planDesignInstance.getAssetsDirId(), planDesignInstance);
        } catch (Exception e) {
            // 回滚方案状态
            rollbackPlan(planDesignInstance, plan, archReview);

            log.error("发布方案及发布视图错误：", e);
            throw new BusinessException(e.getMessage());
        }
        return planDesignInstance.getId();
    }

    @Override
    public void checkQuestion(String businessKey) {
        if (StringUtils.isEmpty(businessKey)) {
            throw new BusinessException("业务主键不能为空!");
        }
        PlanChapterQuestion question = new PlanChapterQuestion();
        question.setPlanId(Long.valueOf(businessKey));
        question.setCheckResult(QuestionCheckEnum.PASS.getCode());
        question.setCreatorCode(SysUtil.getCurrentUserInfo().getLoginCode());
        // 存在待验证的数量
        Long num = planChapterQuestionService.countQuestion(question);
        if (num != null && num > 0) {
            throw new BusinessException("存在未验证通过的问题，提交审批失败!");
        }
    }

    @Override
    public Long checkPublishAssetsDir(String businessKey) {
        if (StringUtils.isEmpty(businessKey)) {
            throw new BusinessException("业务主键不能为空!");
        }
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(Long.valueOf(businessKey));
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案错误!");
        }
        EamCategory category = categorySvc.getById(planDesignInstance.getAssetsDirId(), LibType.DESIGN);
        if (category == null) {
            return -2L;
        }
        return 1L;
    }

    @Override
    public void updateDiagramState(Long planId, Integer status) {
        if (planId == null) {
            throw new BusinessException("方案信息不能为空!");
        }
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(planId);
        if (planDesignInstance == null) {
            throw new BusinessException("获取方案错误!");
        }
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("planId", planId));
        List<ChapterContext> contextList = chapterContextDao.getListByQuery(queryBuilder);
        if (!CollectionUtils.isEmpty(contextList)) {
            Set<String> diagramSet = new HashSet<>();
            contextList.forEach(context -> {
                if (context != null && !CollectionUtils.isEmpty(context.getModuleList())) {
                    List<ContextModule> moduleList = context.getModuleList();
                    moduleList.forEach(module -> {
                        PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();
                        if (ChapterDataTypeEnum.PRODUCT.getDataType().equals(moduleDefinition.getType())) {
                            JSONObject jsonObject = JSONObject.parseObject(module.getData());
                            if (jsonObject != null && !StringUtils.isEmpty(jsonObject.getString("diagramId"))) {
                                diagramSet.add(jsonObject.getString("diagramId"));
                            }
                        }
                    });
                }

            });
            // 修改方案中视图状态
            if (!CollectionUtils.isEmpty(diagramSet)) {
                List<String> diagramList = new ArrayList<>(diagramSet);
                fxDiagramSvc.changeFlowByDiagramIds(diagramList, status);
            }
        }
    }

    /**
     * 终止方案
     * @param plan
     */
    public void cancelPlan(PlanDesignInstance plan) {
        // 如果是终止回滚方案状态
        PlanDesignInstance newPlan = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, newPlan);
        // 终止获取提交审批前的方案状态
        String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
        String status = (String)iCacheService.getCache(key);
        if (!StringUtils.isEmpty(status)) {
            newPlan.setStatus(status);
        } else {
            newPlan.setStatus(PlanStatusEnum.draft.name());
        }
        newPlan.setProcessApproval(false);
        newPlan.setTaskId("");
        planDesignInstanceDao.saveOrUpdate(newPlan);
        log.info("终止的方案id：" + newPlan.getId() + ", 方案状态：" + newPlan.getStatus() + ", 方案缓存状态：" + status);
        // 已做终止操作删除缓存
        if (!StringUtils.isEmpty(status)) {
            iCacheService.delKey(key);
        }

        // 发布失败修改视图可编辑状态
        updatePlanDiagramIsFlow(plan.getId(), 0);
        // 终止删除问题和批注
        planChapterQuestionService.deleteQuestionAndAnnotationByPlanId(plan.getId());
    }

    @Override
    public void gtTermPlan(PlanDesignInstance plan) {
        // 如果是终止回滚方案状态
        PlanDesignInstance newPlan = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, newPlan);
        // 终止获取提交审批前的方案状态
        String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
        String status = (String)iCacheService.getCache(key);
        if (!StringUtils.isEmpty(status)) {
            newPlan.setStatus(status);
        } else {
            newPlan.setStatus(PlanStatusEnum.draft.name());
        }
        newPlan.setProcessApproval(false);
        newPlan.setTaskId("");
        planDesignInstanceDao.saveOrUpdate(newPlan);
        log.info("终止的方案id：" + newPlan.getId() + ", 方案状态：" + newPlan.getStatus() + ", 方案缓存状态：" + status);
        // 已做终止操作删除缓存
        if (!StringUtils.isEmpty(status)) {
            iCacheService.delKey(key);
        }
    }

    @Override
    public void gtCancelPlan(PlanDesignInstance plan) {
        // 如果是撤销回滚方案状态
        PlanDesignInstance newPlan = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, newPlan);
        // 撤销获取提交审批前的方案状态
        String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
        String status = (String)iCacheService.getCache(key);
        if (!StringUtils.isEmpty(status)) {
            newPlan.setStatus(status);
        } else {
            newPlan.setStatus(PlanStatusEnum.draft.name());
        }
        newPlan.setProcessApproval(false);
        newPlan.setTaskId("");
        planDesignInstanceDao.saveOrUpdate(newPlan);
        log.info("撤销的方案id：" + newPlan.getId() + ", 方案状态：" + newPlan.getStatus() + ", 方案缓存状态：" + status);
        // 已做撤销操作删除缓存
        if (!StringUtils.isEmpty(status)) {
            iCacheService.delKey(key);
        }
    }

    @Override
    public void gtNoAgreePlan(PlanDesignInstance plan) {
        PlanDesignInstance newPlan = new PlanDesignInstance();
        BeanUtils.copyProperties(plan, newPlan);
        //获取提交审批前的方案状态
        String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
        String status = (String)iCacheService.getCache(key);
        if (!StringUtils.isEmpty(status)) {
            newPlan.setStatus(status);
        } else {
            newPlan.setStatus(PlanStatusEnum.draft.name());
        }
        newPlan.setProcessApproval(false);
        newPlan.setTaskId("");
        planDesignInstanceDao.saveOrUpdate(newPlan);
        log.info("不同意的方案id：" + newPlan.getId() + ", 方案状态：" + newPlan.getStatus() + ", 方案缓存状态：" + status);
        //已做不同意操作删除缓存
        if (!StringUtils.isEmpty(status)) {
            iCacheService.delKey(key);
        }
    }

    @Override
    public Page<PlanDesignInstance> getSortListByQuery(int pageNum, int pageSize, QueryBuilder query, List<SortBuilder<?>> sorts) {
        return planDesignInstanceDao.getSortListByQuery(pageNum, pageSize, query, sorts);
    }

    @Override
    public List<PlanDesignInstance> gtPlanSubmit(List<Long> planIds, Boolean submitNever) {
        //校验下权限
        List<PlanDesignInstance> plans = getByIds(planIds);
        if (CollectionUtils.isEmpty(plans) || plans.size() != planIds.size()) {
            throw new BusinessException("部分方案已被删除，请重新选择评审方案");
        }
        Map<Long, List<PlanDesignShareRecord>> shareRecordMap = shareService.selectByPlanIds(planIds);
        String curLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        for (PlanDesignInstance plan : plans) {
            if (Boolean.TRUE.equals(plan.isProcessApproval())
                    || PlanStatusEnum.approve_edit.name().equals(plan.getStatus())
                    || PlanStatusEnum.approve.name().equals(plan.getStatus())) {
                throw new BusinessException("方案【" + plan.getName() + "】已提交审批，请勿重复提交");
            }
            Map<String,Object> checkResult = checkPlan(plan.getId());
            if (Boolean.FALSE.equals(checkResult.get("result"))
                    || Boolean.FALSE.equals(checkResult.get("assertDirExist"))) {
                throw new BusinessException("方案[" + plan.getName() + "]发布校验未通过");
            }
            //保存方案提交审批前的状态
            if (Boolean.FALSE.equals(plan.isProcessApproval()) && submitNever) {
                String key = Constants.BEFORE_APPROVAL_PLAN + plan.getId();
                iCacheService.setCache(key, plan.getStatus());
            }
            plan.setProcessApproval(true);
            plan.setStatus(PlanStatusEnum.approve.name());
            if (curLoginCode.equals(plan.getCreatorCode())) {
                continue;
            }
            if (!shareRecordMap.containsKey(plan.getId())) {
                throw new BusinessException("暂无方案[" + plan.getName() + "]发布权限");
            }
            List<PlanDesignShareRecord> shareRecords = shareRecordMap.get(plan.getId());
            boolean publishAuth = false;
            for (PlanDesignShareRecord shareRecord : shareRecords) {
                if (curLoginCode.equals(shareRecord.getSharedLoginCode())
                        && PlanSharePermissionEnum.PUBLISH.getFlag().equals(shareRecord.getPermission())) {
                    publishAuth = true;
                    break;
                }
            }
            if (!publishAuth) {
                throw new BusinessException("暂无方案[" + plan.getName() + "]发布权限");
            }
        }
        return plans;
    }

    @Override
    public Page<PlanDesignInstance> findAllPlanList(Integer pageNum, Integer pageSize, String name, String creators, String templateId, String releaseStatus, String ciClassId, String ciCode, List<String> ciCodes) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("assetsType", Constants.DESIGN));
        queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.deleted.name()));
        queryBuilder.mustNot(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.history.name()));

        if (!BinaryUtils.isEmpty(name)) {
            BoolQueryBuilder nameOrCiCodesQuery = QueryBuilders.boolQuery();
            nameOrCiCodesQuery.should(QueryBuilders.wildcardQuery("name.keyword", "*" + name.trim() + "*"));
            if (!BinaryUtils.isEmpty(ciCodes)) {
                nameOrCiCodesQuery.should(QueryBuilders.termsQuery("defaultSystemCiCode.keyword", ciCodes));
            }
            queryBuilder.must(nameOrCiCodesQuery);
        }
        if (!BinaryUtils.isEmpty(creators)) {
            List<String> creatorList = JSON.parseObject(creators, new TypeReference<List<String>>(){});
            if (!BinaryUtils.isEmpty(creatorList)) {
                queryBuilder.must(QueryBuilders.termsQuery("creatorCode.keyword", creatorList));
            }
        }
        if (!BinaryUtils.isEmpty(templateId)) {
            queryBuilder.must(QueryBuilders.termQuery("templateId", Long.valueOf(templateId)));
        }
        // 根据原来状态显示逻辑 反向推测查询逻辑
        if (!BinaryUtils.isEmpty(releaseStatus)) {
            Integer status = Integer.valueOf(releaseStatus);
            if (Objects.equals(status, 1)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.published.name()));
            } else if(Objects.equals(status, 0)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.draft.name()));
                queryBuilder.must(QueryBuilders.termQuery("processApproval", false));
            } else if (Objects.equals(status, 2)) {
                BoolQueryBuilder statusBoolQuery = QueryBuilders.boolQuery();
                statusBoolQuery.should(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.approve.name()));
                BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.draft.name()))
                        .must(QueryBuilders.termQuery("processApproval", true));

                statusBoolQuery.should(nestedBoolQuery);
                queryBuilder.must(statusBoolQuery);
            } else if (Objects.equals(status, 3)) {
                queryBuilder.must(QueryBuilders.termQuery("status.keyword", PlanStatusEnum.approve_edit.name()));
            }
        }
        if (!BinaryUtils.isEmpty(ciClassId)) {
            queryBuilder.must(QueryBuilders.termQuery("defaultSystemClassId", Long.valueOf(ciClassId)));
        }
        if (!BinaryUtils.isEmpty(ciCode)) {
            queryBuilder.must(QueryBuilders.termQuery("defaultSystemCiCode.keyword", ciCode));
        }
        List<SortBuilder<?>> sorts = new LinkedList<>();
        sorts.add(SortBuilders.fieldSort("modifyTime").order(SortOrder.DESC));
        Page<PlanDesignInstance> result = planDesignInstanceDao.getSortListByQuery(pageNum, pageSize, queryBuilder, sorts);
        return result;
    }
}
